Project

General

Profile

Download (175 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * originally based on m0n0wall (http://m0n0.ch/wall)
10
 * Copyright (c) 2004 Manuel Kasper <mk@neon1.net>.
11
 * All rights reserved.
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 * http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25

    
26
/* include all configuration functions */
27
require_once("globals.inc");
28
require_once("util.inc");
29
require_once("gwlb.inc");
30

    
31
function interfaces_bring_up($interface) {
32
	if (!$interface) {
33
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
34
		log_error("Backtrace: " . debug_backtrace());
35
		return;
36
	}
37
	pfSense_interface_flags($interface, IFF_UP);
38
}
39

    
40
/*
41
 * Return the interface array
42
 */
43
function get_interface_arr($flush = false) {
44
	global $interface_arr_cache;
45

    
46
	/* If the cache doesn't exist, build it */
47
	if (!isset($interface_arr_cache) or $flush) {
48
		$interface_arr_cache = pfSense_interface_listget();
49
	}
50

    
51
	return $interface_arr_cache;
52
}
53

    
54
/*
55
 * does_interface_exist($interface): return true or false if a interface is
56
 * detected.
57
 */
58
function does_interface_exist($interface, $flush = true) {
59
	global $config;
60

    
61
	if (!$interface) {
62
		return false;
63
	}
64

    
65
	$ints = get_interface_arr($flush);
66
	if (in_array($interface, $ints)) {
67
		return true;
68
	} else {
69
		return false;
70
	}
71
}
72

    
73
/*
74
 * does_vip_exist($vip): return true or false if a vip is
75
 * configured.
76
 */
77
function does_vip_exist($vip) {
78
	global $config;
79

    
80
	if (!$vip) {
81
		return false;
82
	}
83

    
84

    
85
	switch ($vip['mode']) {
86
		case "carp":
87
		case "ipalias":
88
			/* XXX: Make proper checks? */
89
			$realif = get_real_interface($vip['interface']);
90
			if (!does_interface_exist($realif)) {
91
				return false;
92
			}
93
			break;
94
		case "proxyarp":
95
			/* XXX: Implement this */
96
		default:
97
			return false;
98
	}
99

    
100
	$ifacedata = pfSense_getall_interface_addresses($realif);
101
	foreach ($ifacedata as $vipips) {
102
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}") {
103
			return true;
104
		}
105
	}
106

    
107
	return false;
108
}
109

    
110
function interface_netgraph_needed($interface = "wan") {
111
	global $config;
112

    
113
	$found = false;
114
	if (!empty($config['l2tp']) &&
115
	    $config['l2tp']['mode'] == "server") {
116
		$found = true;
117
	}
118
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
119
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
120
			if ($pppoe['mode'] != "server") {
121
				continue;
122
			}
123
			if ($pppoe['interface'] == $interface) {
124
				$found = true;
125
				break;
126
			}
127
		}
128
	}
129
	if ($found == false) {
130
		$found = interface_isppp_type($interface);
131
	}
132

    
133
	if ($found == false) {
134
		$realif = get_real_interface($interface);
135
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
136
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
137
				$ports = explode(',', $ppp['ports']);
138
				foreach ($ports as $pid => $port) {
139
					$port = get_real_interface($port);
140
					if ($realif == $port) {
141
						$found = true;
142
						break;
143
					}
144
					/* Find the parent interfaces of the vlans in the MLPPP configs
145
					* there should be only one element in the array here
146
					* -- this could be better . . . */
147
					$parent_if = get_parent_interface($port);
148
					if ($realif == $parent_if[0]) {
149
						$found = true;
150
						break;
151
					}
152
				}
153
			}
154
		}
155
	}
156

    
157
	if ($found == false) {
158
		$realif = get_real_interface($interface);
159
		pfSense_ngctl_detach("{$realif}:", $realif);
160
	}
161
	/* NOTE: We make sure for this on interface_ppps_configure()
162
	 *	no need to do it here again.
163
	 *	else
164
	 *		pfSense_ngctl_attach(".", $realif);
165
	 */
166
}
167

    
168
function interfaces_loopback_configure() {
169
	global $g;
170

    
171
	if (platform_booting()) {
172
		echo gettext("Configuring loopback interface...");
173
	}
174
	pfSense_interface_setaddress("lo0", "127.0.0.1");
175
	interfaces_bring_up("lo0");
176
	if (platform_booting()) {
177
		echo gettext("done.") . "\n";
178
	}
179
	return 0;
180
}
181

    
182
function interfaces_vlan_configure($realif = "") {
183
	global $config, $g;
184
	if (platform_booting()) {
185
		echo gettext("Configuring VLAN interfaces...");
186
	}
187
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
188
		foreach ($config['vlans']['vlan'] as $vlan) {
189
			if (empty($vlan['vlanif'])) {
190
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
191
			}
192
			if (!empty($realif) && $realif != $vlan['vlanif']) {
193
				continue;
194
			}
195

    
196
			/* XXX: Maybe we should report any errors?! */
197
			interface_vlan_configure($vlan);
198
		}
199
	}
200
	if (platform_booting()) {
201
		echo gettext("done.") . "\n";
202
	}
203
}
204

    
205
function interface_vlan_configure(&$vlan) {
206
	global $config, $g;
207

    
208
	if (!is_array($vlan)) {
209
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
210
		return;
211
	}
212
	$if = $vlan['if'];
213
	if (empty($if)) {
214
		log_error(gettext("interface_vlan_configure called with if undefined."));
215
		return;
216
	}
217

    
218
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
219
	$tag = $vlan['tag'];
220
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
221

    
222
	/* make sure the parent interface is up */
223
	interfaces_bring_up($if);
224
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
225
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
226

    
227
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
228
		pfSense_interface_destroy($vlanif);
229
	}
230

    
231
	$tmpvlanif = pfSense_interface_create("vlan");
232
	pfSense_interface_rename($tmpvlanif, $vlanif);
233
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
234

    
235
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
236

    
237
	interfaces_bring_up($vlanif);
238

    
239
	/* invalidate interface cache */
240
	get_interface_arr(true);
241

    
242
	/* configure interface if assigned */
243
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
244
	if ($assignedif) {
245
		if (isset($config['interfaces'][$assignedif]['enable'])) {
246
			interface_configure($assignedif, true);
247
		}
248
	}
249

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

    
253
	return $vlanif;
254
}
255

    
256
function interface_qinq_configure(&$vlan, $fd = NULL) {
257
	global $config, $g;
258

    
259
	if (!is_array($vlan)) {
260
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
261
		return;
262
	}
263

    
264
	$qinqif = $vlan['if'];
265
	$tag = $vlan['tag'];
266
	if (empty($qinqif)) {
267
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
268
		return;
269
	}
270

    
271
	if (!does_interface_exist($qinqif)) {
272
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
273
		return;
274
	}
275

    
276
	$vlanif = interface_vlan_configure($vlan);
277

    
278
	if ($fd == NULL) {
279
		$exec = true;
280
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
281
	} else {
282
		$exec = false;
283
	}
284
	/* make sure the parent is converted to ng_vlan(4) and is up */
285
	interfaces_bring_up($qinqif);
286

    
287
	pfSense_ngctl_attach(".", $qinqif);
288
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
289
		fwrite($fd, "shutdown {$vlanif}qinq:\n");
290
		exec("/usr/sbin/ngctl msg {$vlanif}qinq: gettable", $result);
291
		if (empty($result)) {
292
			fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n");
293
			fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n");
294
			fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n");
295
		}
296
	} else {
297
		fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n");
298
		fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n");
299
		fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n");
300
	}
301

    
302
	/* invalidate interface cache */
303
	get_interface_arr(true);
304

    
305
	if (!stristr($qinqif, "_vlan")) {
306
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
307
	}
308

    
309
	$macaddr = get_interface_mac($qinqif);
310
	if (!empty($vlan['members'])) {
311
		$members = explode(" ", $vlan['members']);
312
		foreach ($members as $qtag) {
313
			$qinq = array();
314
			$qinq['tag'] = $qtag;
315
			$qinq['if'] = $vlanif;
316
			interface_qinq2_configure($qinq, $fd, $macaddr);
317
		}
318
	}
319
	if ($exec == true) {
320
		fclose($fd);
321
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
322
	}
323

    
324
	interfaces_bring_up($qinqif);
325
	if (!empty($vlan['members'])) {
326
		$members = explode(" ", $vlan['members']);
327
		foreach ($members as $qif) {
328
			interfaces_bring_up("{$vlanif}_{$qif}");
329
		}
330
	}
331

    
332
	return $vlanif;
333
}
334

    
335
function interfaces_qinq_configure() {
336
	global $config, $g;
337
	if (platform_booting()) {
338
		echo gettext("Configuring QinQ interfaces...");
339
	}
340
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
341
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
342
			/* XXX: Maybe we should report any errors?! */
343
			interface_qinq_configure($qinq);
344
		}
345
	}
346
	if (platform_booting()) {
347
		echo gettext("done.") . "\n";
348
	}
349
}
350

    
351
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
352
	global $config, $g;
353

    
354
	if (!is_array($qinq)) {
355
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
356
		return;
357
	}
358

    
359
	$if = $qinq['if'];
360
	$tag = $qinq['tag'];
361
	$vlanif = "{$if}_{$tag}";
362
	if (empty($if)) {
363
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
364
		return;
365
	}
366

    
367
	fwrite($fd, "shutdown {$if}h{$tag}:\n");
368
	fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
369
	fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
370
	fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
371
	fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
372
	fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
373

    
374
	/* invalidate interface cache */
375
	get_interface_arr(true);
376

    
377
	return $vlanif;
378
}
379

    
380
function interfaces_create_wireless_clones() {
381
	global $config, $g;
382

    
383
	if (platform_booting()) {
384
		echo gettext("Creating wireless clone interfaces...");
385
	}
386

    
387
	$iflist = get_configured_interface_list();
388

    
389
	foreach ($iflist as $if) {
390
		$realif = $config['interfaces'][$if]['if'];
391
		if (is_interface_wireless($realif)) {
392
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
393
		}
394
	}
395

    
396
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
397
		foreach ($config['wireless']['clone'] as $clone) {
398
			if (empty($clone['cloneif'])) {
399
				continue;
400
			}
401
			if (does_interface_exist($clone['cloneif'])) {
402
				continue;
403
			}
404
			/* XXX: Maybe we should report any errors?! */
405
			interface_wireless_clone($clone['cloneif'], $clone);
406
		}
407
	}
408
	if (platform_booting()) {
409
		echo gettext("done.") . "\n";
410
	}
411

    
412
}
413

    
414
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
415
	global $config;
416

    
417
	$i = 0;
418
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
419
		foreach ($config['bridges']['bridged'] as $bridge) {
420
			if (empty($bridge['bridgeif'])) {
421
				$bridge['bridgeif'] = "bridge{$i}";
422
			}
423
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
424
				continue;
425
			}
426

    
427
			if ($checkmember == 1) {
428
				/* XXX: It should not be possible no? */
429
				if (strstr($bridge['if'], '_vip')) {
430
					continue;
431
				}
432
				$members = explode(',', $bridge['members']);
433
				foreach ($members as $member) {
434
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
435
						continue 2;
436
					}
437
				}
438
			}
439
			else if ($checkmember == 2) {
440
				$members = explode(',', $bridge['members']);
441
				foreach ($members as $member) {
442
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
443
						continue 2;
444
					}
445
				}
446
			}
447
			/* XXX: Maybe we should report any errors?! */
448
			interface_bridge_configure($bridge, $checkmember);
449
			$i++;
450
		}
451
	}
452
}
453

    
454
function interface_bridge_configure(&$bridge, $checkmember = 0) {
455
	global $config, $g;
456

    
457
	if (!is_array($bridge)) {
458
		return;
459
	}
460

    
461
	if (empty($bridge['members'])) {
462
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
463
		return;
464
	}
465

    
466
	$members = explode(',', $bridge['members']);
467
	if (!count($members)) {
468
		return;
469
	}
470

    
471
	/* Calculate smaller mtu and enforce it */
472
	$smallermtu = 0;
473
	$foundgif = false;
474
	foreach ($members as $member) {
475
		$realif = get_real_interface($member);
476
		$mtu = get_interface_mtu($realif);
477
		if (substr($realif, 0, 3) == "gif") {
478
			$foundgif = true;
479
			if ($checkmember == 1) {
480
				return;
481
			}
482
			if ($mtu <= 1500) {
483
				continue;
484
			}
485
		}
486
		if ($smallermtu == 0 && !empty($mtu)) {
487
			$smallermtu = $mtu;
488
		} else if (!empty($mtu) && $mtu < $smallermtu) {
489
			$smallermtu = $mtu;
490
		}
491
	}
492
	if ($foundgif == false && $checkmember == 2) {
493
		return;
494
	}
495

    
496
	/* Just in case anything is not working well */
497
	if ($smallermtu == 0) {
498
		$smallermtu = 1500;
499
	}
500

    
501
	if (!empty($bridge['bridgeif'])) {
502
		pfSense_interface_destroy($bridge['bridgeif']);
503
		pfSense_interface_create($bridge['bridgeif']);
504
		$bridgeif = escapeshellarg($bridge['bridgeif']);
505
	} else {
506
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
507
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
508
		$bridgeif = pfSense_interface_create("bridge");
509
		$bridge['bridgeif'] = $bridgeif;
510
	}
511

    
512
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
513
	if ($bridgemtu > $smallermtu) {
514
		$smallermtu = $bridgemtu;
515
	}
516

    
517
	$checklist = get_configured_interface_list();
518

    
519
	/* Add interfaces to bridge */
520
	foreach ($members as $member) {
521
		if (empty($checklist[$member])) {
522
			continue;
523
		}
524
		$realif = get_real_interface($member);
525
		if (!$realif) {
526
			log_error(gettext("realif not defined in interfaces bridge - up"));
527
			continue;
528
		}
529
		/* make sure the parent interface is up */
530
		pfSense_interface_mtu($realif, $smallermtu);
531
		interfaces_bring_up($realif);
532
		enable_hardware_offloading($member);
533
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
534
	}
535

    
536
	if (isset($bridge['enablestp'])) {
537
		interface_bridge_configure_stp($bridge);
538
	}
539

    
540
	interface_bridge_configure_advanced($bridge);
541

    
542
	if ($bridge['bridgeif']) {
543
		interfaces_bring_up($bridge['bridgeif']);
544
	} else {
545
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
546
	}
547
}
548

    
549
function interface_bridge_configure_stp($bridge) {
550
	if (isset($bridge['enablestp'])) {
551
		$bridgeif = $bridge['bridgeif'];
552
		/* configure spanning tree proto */
553
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
554

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

    
608
function interface_bridge_configure_advanced($bridge) {
609
	$bridgeif = $bridge['bridgeif'];
610

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

    
668
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
669
	global $config;
670

    
671
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
672
		return;
673
	}
674

    
675
	if ($flagsapplied == false) {
676
		$mtu = get_interface_mtu($bridgeif);
677
		$mtum = get_interface_mtu($interface);
678
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
679
			pfSense_interface_mtu($interface, $mtu);
680
		}
681

    
682
		hardware_offloading_applyflags($interface);
683
		interfaces_bring_up($interface);
684
	}
685

    
686
	pfSense_bridge_add_member($bridgeif, $interface);
687
	if (is_array($config['bridges']['bridged'])) {
688
		foreach ($config['bridges']['bridged'] as $bridge) {
689
			if ($bridgeif == $bridge['bridgeif']) {
690
				interface_bridge_configure_stp($bridge);
691
				interface_bridge_configure_advanced($bridge);
692
			}
693
		}
694
	}
695
}
696

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

    
721
function interface_lagg_configure($lagg) {
722
	global $config, $g;
723

    
724
	if (!is_array($lagg)) {
725
		return -1;
726
	}
727

    
728
	$members = explode(',', $lagg['members']);
729
	if (!count($members)) {
730
		return -1;
731
	}
732

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

    
741
	/* Check if MTU was defined for this lagg interface */
742
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
743
	if ($lagg_mtu == 0 &&
744
	    is_array($config['interfaces'])) {
745
		foreach ($config['interfaces'] as $tmpinterface) {
746
			if ($tmpinterface['if'] == $lagg['laggif'] &&
747
			    !empty($tmpinterface['mtu'])) {
748
				$lagg_mtu = $tmpinterface['mtu'];
749
				break;
750
			}
751
		}
752
	}
753

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

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

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

    
772
	interfaces_bring_up($laggif);
773

    
774
	return $laggif;
775
}
776

    
777
function interfaces_gre_configure($checkparent = 0, $realif = "") {
778
	global $config;
779

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

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

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

    
815
	if (!is_array($gre)) {
816
		return -1;
817
	}
818

    
819
	$realif = get_real_interface($gre['if']);
820
	$realifip = get_interface_ip($gre['if']);
821
	$realifip6 = get_interface_ipv6($gre['if']);
822

    
823
	/* make sure the parent interface is up */
824
	interfaces_bring_up($realif);
825

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

    
834
	/* Do not change the order here for more see gre(4) NOTES section. */
835
	if (is_ipaddrv6($gre['remote-addr'])) {
836
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
837
	} else {
838
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
839
	}
840
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
841
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
842
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
843
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
844
	} else {
845
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
846
	}
847

    
848
	if ($greif) {
849
		interfaces_bring_up($greif);
850
	} else {
851
		log_error(gettext("Could not bring greif up -- variable not defined."));
852
	}
853

    
854
	if (isset($gre['link1']) && $gre['link1']) {
855
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
856
	}
857
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
858
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
859
	}
860
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
861
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
862
	}
863

    
864
	interfaces_bring_up($greif);
865

    
866
	return $greif;
867
}
868

    
869
function interfaces_gif_configure($checkparent = 0, $realif = "") {
870
	global $config;
871

    
872
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
873
		foreach ($config['gifs']['gif'] as $i => $gif) {
874
			if (empty($gif['gifif'])) {
875
				$gre['gifif'] = "gif{$i}";
876
			}
877
			if (!empty($realif) && $realif != $gif['gifif']) {
878
				continue;
879
			}
880

    
881
			if ($checkparent == 1) {
882
				if (substr($gif['if'], 0, 4) == '_vip') {
883
					continue;
884
				}
885
				if (substr($gif['if'], 0, 5) == '_lloc') {
886
					continue;
887
				}
888
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
889
					continue;
890
				}
891
			}
892
			else if ($checkparent == 2) {
893
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
894
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
895
					continue;
896
				}
897
			}
898
			/* XXX: Maybe we should report any errors?! */
899
			interface_gif_configure($gif);
900
		}
901
	}
902
}
903

    
904
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
905
function interface_gif_configure(&$gif, $gifkey = "") {
906
	global $config, $g;
907

    
908
	if (!is_array($gif)) {
909
		return -1;
910
	}
911

    
912
	$realif = get_real_interface($gif['if']);
913
	$ipaddr = get_interface_ip($gif['if']);
914

    
915
	if (is_ipaddrv4($gif['remote-addr'])) {
916
		if (is_ipaddrv4($ipaddr)) {
917
			$realifip = $ipaddr;
918
		} else {
919
			$realifip = get_interface_ip($gif['if']);
920
		}
921
		$realifgw = get_interface_gateway($gif['if']);
922
	} else if (is_ipaddrv6($gif['remote-addr'])) {
923
		if (is_ipaddrv6($ipaddr)) {
924
			$realifip = $ipaddr;
925
		} else {
926
			$realifip = get_interface_ipv6($gif['if']);
927
		}
928
		$realifgw = get_interface_gateway_v6($gif['if']);
929
	}
930
	/* make sure the parent interface is up */
931
	if ($realif) {
932
		interfaces_bring_up($realif);
933
	} else {
934
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
935
	}
936

    
937
	if (platform_booting() || !(empty($gif['gifif']))) {
938
		pfSense_interface_destroy($gif['gifif']);
939
		pfSense_interface_create($gif['gifif']);
940
		$gifif = $gif['gifif'];
941
	} else {
942
		$gifif = pfSense_interface_create("gif");
943
	}
944

    
945
	/* Do not change the order here for more see gif(4) NOTES section. */
946
	if (is_ipaddrv6($gif['remote-addr'])) {
947
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
948
	} else {
949
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
950
	}
951
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
952
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
953
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
954
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
955
	} else {
956
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
957
	}
958
	if (isset($gif['link1'])) {
959
		pfSense_interface_flags($gifif, IFF_LINK1);
960
	}
961
	if (isset($gif['link2'])) {
962
		pfSense_interface_flags($gifif, IFF_LINK2);
963
	}
964
	if ($gifif) {
965
		interfaces_bring_up($gifif);
966
		$gifmtu = "";
967
		$currentgifmtu = get_interface_mtu($gifif);
968
		foreach ($config['interfaces'] as $tmpinterface) {
969
			if ($tmpinterface['if'] == $gifif) {
970
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
971
					$gifmtu = $tmpinterface['mtu'];
972
				}
973
			}
974
		}
975
		if (is_numericint($gifmtu)) {
976
			if ($gifmtu != $currentgifmtu) {
977
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
978
			}
979
		}
980
	} else {
981
		log_error(gettext("could not bring gifif up -- variable not defined"));
982
	}
983

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

    
1000

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

    
1008
	if (is_ipaddrv4($realifgw)) {
1009
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1010
	}
1011
	if (is_ipaddrv6($realifgw)) {
1012
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1013
	}
1014

    
1015
	interfaces_bring_up($gifif);
1016

    
1017
	return $gifif;
1018
}
1019

    
1020
function interfaces_configure() {
1021
	global $config, $g;
1022

    
1023
	/* Set up our loopback interface */
1024
	interfaces_loopback_configure();
1025

    
1026
	/* create the unconfigured wireless clones */
1027
	interfaces_create_wireless_clones();
1028

    
1029
	/* set up LAGG virtual interfaces */
1030
	interfaces_lagg_configure();
1031

    
1032
	/* set up VLAN virtual interfaces */
1033
	interfaces_vlan_configure();
1034

    
1035
	interfaces_qinq_configure();
1036

    
1037
	$iflist = get_configured_interface_with_descr();
1038
	$delayed_list = array();
1039
	$bridge_list = array();
1040
	$track6_list = array();
1041

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

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

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

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

    
1082
	/* set up GRE virtual interfaces */
1083
	interfaces_gre_configure(1);
1084

    
1085
	/* set up GIF virtual interfaces */
1086
	interfaces_gif_configure(1);
1087

    
1088
	/* set up BRIDGe virtual interfaces */
1089
	interfaces_bridge_configure(1);
1090

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

    
1099
		interface_configure($if, $reload);
1100

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

    
1106
	/* bring up vip interfaces */
1107
	interfaces_vips_configure();
1108

    
1109
	/* set up GRE virtual interfaces */
1110
	interfaces_gre_configure(2);
1111

    
1112
	/* set up GIF virtual interfaces */
1113
	interfaces_gif_configure(2);
1114

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

    
1123
		interface_configure($if, $reload);
1124

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

    
1130
	/* set up BRIDGe virtual interfaces */
1131
	interfaces_bridge_configure(2);
1132

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

    
1141
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1142
		// redmine #3997
1143
		interface_reconfigure($if, $reload);
1144
		interfaces_vips_configure($if);
1145

    
1146
		if (platform_booting()) {
1147
			echo gettext("done.") . "\n";
1148
		}
1149
	}
1150

    
1151
	/* configure interface groups */
1152
	interfaces_group_setup();
1153

    
1154
	if (!platform_booting()) {
1155
		/* reconfigure static routes (kernel may have deleted them) */
1156
		system_routing_configure();
1157

    
1158
		/* reload IPsec tunnels */
1159
		vpn_ipsec_configure();
1160

    
1161
		/* restart dns servers (defering dhcpd reload) */
1162
		if (isset($config['dnsmasq']['enable'])) {
1163
			services_dnsmasq_configure(false);
1164
		}
1165
		if (isset($config['unbound']['enable'])) {
1166
			services_unbound_configure(false);
1167
		}
1168

    
1169
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1170
		services_dhcpd_configure();
1171
	}
1172

    
1173
	return 0;
1174
}
1175

    
1176
function interface_reconfigure($interface = "wan", $reloadall = false) {
1177
	interface_bring_down($interface);
1178
	interface_configure($interface, $reloadall);
1179
}
1180

    
1181
function interface_vip_bring_down($vip) {
1182
	global $g;
1183

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

    
1213
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1214
	global $config, $g;
1215

    
1216
	if (!isset($config['interfaces'][$interface])) {
1217
		return;
1218
	}
1219

    
1220
	if ($g['debug']) {
1221
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1222
	}
1223

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

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

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

    
1361
	if (!empty($track6) && is_array($track6)) {
1362
		if (!function_exists('services_dhcpd_configure')) {
1363
			require_once('services.inc');
1364
		}
1365
		/* Bring down radvd and dhcp6 on these interfaces */
1366
		services_dhcpd_configure('inet6', $track6);
1367
	}
1368

    
1369
	$old_router = '';
1370
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1371
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1372
	}
1373

    
1374
	/* remove interface up file if it exists */
1375
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1376
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1377
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1378
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1379
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1380
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1381
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1382

    
1383
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1384
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1385
	if (is_array($ifcfg['wireless'])) {
1386
		kill_hostapd($realif);
1387
		mwexec(kill_wpasupplicant($realif));
1388
	}
1389

    
1390
	if ($destroy == true) {
1391
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1392
			pfSense_interface_destroy($realif);
1393
		}
1394
	}
1395

    
1396
	return;
1397
}
1398

    
1399
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1400
	global $config;
1401
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1402
		unset($config["virtualip_carp_maintenancemode"]);
1403
		write_config("Leave CARP maintenance mode");
1404
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1405
		$config["virtualip_carp_maintenancemode"] = true;
1406
		write_config(gettext("Enter CARP maintenance mode"));
1407
	}
1408

    
1409
	$viparr = &$config['virtualip']['vip'];
1410
	foreach ($viparr as $vip) {
1411
		if ($vip['mode'] == "carp") {
1412
			interface_carp_configure($vip);
1413
		}
1414
	}
1415
}
1416

    
1417
function interface_wait_tentative($interface, $timeout = 10) {
1418
	if (!does_interface_exist($interface)) {
1419
		return false;
1420
	}
1421

    
1422
	$time = 0;
1423
	while ($time <= $timeout) {
1424
		$if = pfSense_get_interface_addresses($interface);
1425
		if (!isset($if['tentative'])) {
1426
			return true;
1427
		}
1428
		sleep(1);
1429
		$time++;
1430
	}
1431

    
1432
	return false;
1433
}
1434

    
1435
function interface_isppp_type($interface) {
1436
	global $config;
1437

    
1438
	if (!is_array($config['interfaces'][$interface])) {
1439
		return false;
1440
	}
1441

    
1442
	switch ($config['interfaces'][$interface]['ipaddr']) {
1443
		case 'pptp':
1444
		case 'l2tp':
1445
		case 'pppoe':
1446
		case 'ppp':
1447
			return true;
1448
			break;
1449
		default:
1450
			return false;
1451
			break;
1452
	}
1453
}
1454

    
1455
function interfaces_ptpid_used($ptpid) {
1456
	global $config;
1457

    
1458
	if (is_array($config['ppps']['ppp'])) {
1459
		foreach ($config['ppps']['ppp'] as & $settings) {
1460
			if ($ptpid == $settings['ptpid']) {
1461
				return true;
1462
			}
1463
		}
1464
	}
1465

    
1466
	return false;
1467
}
1468

    
1469
function interfaces_ptpid_next() {
1470

    
1471
	$ptpid = 0;
1472
	while (interfaces_ptpid_used($ptpid)) {
1473
		$ptpid++;
1474
	}
1475

    
1476
	return $ptpid;
1477
}
1478

    
1479
function getMPDCRONSettings($pppif) {
1480
	global $config;
1481

    
1482
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1483
	if (is_array($config['cron']['item'])) {
1484
		foreach ($config['cron']['item'] as $i => $item) {
1485
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1486
				return array("ID" => $i, "ITEM" => $item);
1487
			}
1488
		}
1489
	}
1490

    
1491
	return NULL;
1492
}
1493

    
1494
function handle_pppoe_reset($post_array) {
1495
	global $config, $g;
1496

    
1497
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1498
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1499

    
1500
	if (!is_array($config['cron']['item'])) {
1501
		$config['cron']['item'] = array();
1502
	}
1503

    
1504
	$itemhash = getMPDCRONSettings($pppif);
1505

    
1506
	// reset cron items if necessary and return
1507
	if (empty($post_array['pppoe-reset-type'])) {
1508
		if (isset($itemhash)) {
1509
			unset($config['cron']['item'][$itemhash['ID']]);
1510
		}
1511
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1512
		return;
1513
	}
1514

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

    
1577
/*
1578
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1579
 * It writes the mpd config file to /var/etc every time the link is opened.
1580
 */
1581
function interface_ppps_configure($interface) {
1582
	global $config, $g;
1583

    
1584
	/* Return for unassigned interfaces. This is a minimum requirement. */
1585
	if (empty($config['interfaces'][$interface])) {
1586
		return 0;
1587
	}
1588
	$ifcfg = $config['interfaces'][$interface];
1589
	if (!isset($ifcfg['enable'])) {
1590
		return 0;
1591
	}
1592

    
1593
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1594
	if (!is_dir("/var/spool/lock")) {
1595
		mkdir("/var/spool/lock", 0777, true);
1596
	}
1597
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1598
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1599
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1600
	}
1601

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

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

    
1631
	$ports = explode(',', $ppp['ports']);
1632
	if ($type != "modem") {
1633
		foreach ($ports as $pid => $port) {
1634
			$ports[$pid] = get_real_interface($port);
1635
			if (empty($ports[$pid])) {
1636
				return 0;
1637
			}
1638
		}
1639
	}
1640
	$localips = explode(',', $ppp['localip']);
1641
	$gateways = explode(',', $ppp['gateway']);
1642
	$subnets = explode(',', $ppp['subnet']);
1643

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

    
1667
				if (!is_ipaddr($localips[$pid])) {
1668
					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));
1669
					$localips[$pid] = "0.0.0.0";
1670
				}
1671
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1672
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1673
				}
1674
				if (!is_ipaddr($gateways[$pid])) {
1675
					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));
1676
					return 0;
1677
				}
1678
				pfSense_ngctl_attach(".", $port);
1679
				break;
1680
			case "ppp":
1681
				if (!file_exists("{$port}")) {
1682
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1683
					return 0;
1684
				}
1685
				break;
1686
			default:
1687
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1688
				break;
1689
		}
1690
	}
1691

    
1692
	if (is_array($ports) && count($ports) > 1) {
1693
		$multilink = "enable";
1694
	} else {
1695
		$multilink = "disable";
1696
	}
1697

    
1698
	if ($type == "modem") {
1699
		if (is_ipaddr($ppp['localip'])) {
1700
			$localip = $ppp['localip'];
1701
		} else {
1702
			$localip = '0.0.0.0';
1703
		}
1704

    
1705
		if (is_ipaddr($ppp['gateway'])) {
1706
			$gateway = $ppp['gateway'];
1707
		} else {
1708
			$gateway = "10.64.64.{$pppid}";
1709
		}
1710
		$ranges = "{$localip}/0 {$gateway}/0";
1711

    
1712
		if (empty($ppp['apnum'])) {
1713
			$ppp['apnum'] = 1;
1714
		}
1715
	} else {
1716
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1717
	}
1718

    
1719
	if (isset($ppp['ondemand'])) {
1720
		$ondemand = "enable";
1721
	} else {
1722
		$ondemand = "disable";
1723
	}
1724
	if (!isset($ppp['idletimeout'])) {
1725
		$ppp['idletimeout'] = 0;
1726
	}
1727

    
1728
	if (empty($ppp['username']) && $type == "modem") {
1729
		$ppp['username'] = "user";
1730
		$ppp['password'] = "none";
1731
	}
1732
	if (empty($ppp['password']) && $type == "modem") {
1733
		$passwd = "none";
1734
	} else {
1735
		$passwd = base64_decode($ppp['password']);
1736
	}
1737

    
1738
	$bandwidths = explode(',', $ppp['bandwidth']);
1739
	$defaultmtu = "1492";
1740
	if (!empty($ifcfg['mtu'])) {
1741
		$defaultmtu = intval($ifcfg['mtu']);
1742
	}
1743
	if (isset($ppp['mtu'])) {
1744
		$mtus = explode(',', $ppp['mtu']);
1745
	}
1746
	if (isset($ppp['mru'])) {
1747
		$mrus = explode(',', $ppp['mru']);
1748
	}
1749
	if (isset($ppp['mrru'])) {
1750
		$mrrus = explode(',', $ppp['mrru']);
1751
	}
1752

    
1753
	// Construct the mpd.conf file
1754
	$mpdconf = <<<EOD
1755
startup:
1756
	# configure the console
1757
	set console close
1758
	# configure the web server
1759
	set web close
1760

    
1761
default:
1762
{$ppp['type']}client:
1763
	create bundle static {$interface}
1764
	set bundle enable ipv6cp
1765
	set iface name {$pppif}
1766

    
1767
EOD;
1768
	$setdefaultgw = false;
1769
	$founddefaultgw = false;
1770
	if (is_array($config['gateways']['gateway_item'])) {
1771
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1772
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1773
				$setdefaultgw = true;
1774
				break;
1775
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1776
				$founddefaultgw = true;
1777
				break;
1778
			}
1779
		}
1780
	}
1781

    
1782
/* Omit this, we maintain the default route by other means, and it causes problems with
1783
 * default gateway switching. See redmine #1837 for original issue
1784
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
1785
 * edge case. redmine #6495 open to address.
1786
 */
1787
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1788
		$setdefaultgw = true;
1789
		$mpdconf .= <<<EOD
1790
	set iface route default
1791

    
1792
EOD;
1793
	}
1794
	$mpdconf .= <<<EOD
1795
	set iface {$ondemand} on-demand
1796
	set iface idle {$ppp['idletimeout']}
1797

    
1798
EOD;
1799

    
1800
	if (isset($ppp['ondemand'])) {
1801
		$mpdconf .= <<<EOD
1802
	set iface addrs 10.10.1.1 10.10.1.2
1803

    
1804
EOD;
1805
	}
1806

    
1807
	if (isset($ppp['tcpmssfix'])) {
1808
		$tcpmss = "disable";
1809
	} else {
1810
		$tcpmss = "enable";
1811
	}
1812
	$mpdconf .= <<<EOD
1813
	set iface {$tcpmss} tcpmssfix
1814

    
1815
EOD;
1816

    
1817
	$mpdconf .= <<<EOD
1818
	set iface up-script /usr/local/sbin/ppp-linkup
1819
	set iface down-script /usr/local/sbin/ppp-linkdown
1820
	set ipcp ranges {$ranges}
1821

    
1822
EOD;
1823
	if (isset($ppp['vjcomp'])) {
1824
		$mpdconf .= <<<EOD
1825
	set ipcp no vjcomp
1826

    
1827
EOD;
1828
	}
1829

    
1830
	if (isset($config['system']['dnsallowoverride'])) {
1831
		$mpdconf .= <<<EOD
1832
	set ipcp enable req-pri-dns
1833
	set ipcp enable req-sec-dns
1834

    
1835
EOD;
1836
	}
1837

    
1838
	if (!isset($ppp['verbose_log'])) {
1839
		$mpdconf .= <<<EOD
1840
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1841

    
1842
EOD;
1843
	}
1844

    
1845
	foreach ($ports as $pid => $port) {
1846
		$port = get_real_interface($port);
1847
		$mpdconf .= <<<EOD
1848

    
1849
	create link static {$interface}_link{$pid} {$type}
1850
	set link action bundle {$interface}
1851
	set link {$multilink} multilink
1852
	set link keep-alive 10 60
1853
	set link max-redial 0
1854

    
1855
EOD;
1856
		if (isset($ppp['shortseq'])) {
1857
			$mpdconf .= <<<EOD
1858
	set link no shortseq
1859

    
1860
EOD;
1861
		}
1862

    
1863
		if (isset($ppp['acfcomp'])) {
1864
			$mpdconf .= <<<EOD
1865
	set link no acfcomp
1866

    
1867
EOD;
1868
		}
1869

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

    
1874
EOD;
1875
		}
1876

    
1877
		$mpdconf .= <<<EOD
1878
	set link disable chap pap
1879
	set link accept chap pap eap
1880
	set link disable incoming
1881

    
1882
EOD;
1883

    
1884

    
1885
		if (!empty($bandwidths[$pid])) {
1886
			$mpdconf .= <<<EOD
1887
	set link bandwidth {$bandwidths[$pid]}
1888

    
1889
EOD;
1890
		}
1891

    
1892
		if (empty($mtus[$pid])) {
1893
			$mtus[$pid] = $defaultmtu;
1894
		}
1895
		if ($type == "pppoe") {
1896
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1897
				$mtus[$pid] = get_interface_mtu($port) - 8;
1898
			}
1899
		}
1900
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1901
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1902
			$mpdconf .= <<<EOD
1903
	set link mtu {$mtus[$pid]}
1904

    
1905
EOD;
1906
		}
1907

    
1908
		if (!empty($mrus[$pid])) {
1909
			$mpdconf .= <<<EOD
1910
	set link mru {$mrus[$pid]}
1911

    
1912
EOD;
1913
		}
1914

    
1915
		if (!empty($mrrus[$pid])) {
1916
			$mpdconf .= <<<EOD
1917
	set link mrru {$mrrus[$pid]}
1918

    
1919
EOD;
1920
		}
1921

    
1922
		$mpdconf .= <<<EOD
1923
	set auth authname "{$ppp['username']}"
1924
	set auth password {$passwd}
1925

    
1926
EOD;
1927
		if ($type == "modem") {
1928
			$mpdconf .= <<<EOD
1929
	set modem device {$ppp['ports']}
1930
	set modem script DialPeer
1931
	set modem idle-script Ringback
1932
	set modem watch -cd
1933
	set modem var \$DialPrefix "DT"
1934
	set modem var \$Telephone "{$ppp['phone']}"
1935

    
1936
EOD;
1937
		}
1938
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1939
			$mpdconf .= <<<EOD
1940
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1941

    
1942
EOD;
1943
		}
1944
		if (isset($ppp['initstr']) && $type == "modem") {
1945
			$initstr = base64_decode($ppp['initstr']);
1946
			$mpdconf .= <<<EOD
1947
	set modem var \$InitString "{$initstr}"
1948

    
1949
EOD;
1950
		}
1951
		if (isset($ppp['simpin']) && $type == "modem") {
1952
			if ($ppp['pin-wait'] == "") {
1953
				$ppp['pin-wait'] = 0;
1954
			}
1955
			$mpdconf .= <<<EOD
1956
	set modem var \$SimPin "{$ppp['simpin']}"
1957
	set modem var \$PinWait "{$ppp['pin-wait']}"
1958

    
1959
EOD;
1960
		}
1961
		if (isset($ppp['apn']) && $type == "modem") {
1962
			$mpdconf .= <<<EOD
1963
	set modem var \$APN "{$ppp['apn']}"
1964
	set modem var \$APNum "{$ppp['apnum']}"
1965

    
1966
EOD;
1967
		}
1968
		if ($type == "pppoe") {
1969
			// Send a null service name if none is set.
1970
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1971
			$mpdconf .= <<<EOD
1972
	set pppoe service "{$provider}"
1973

    
1974
EOD;
1975
		}
1976
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
1977
			$mpdconf .= <<<EOD
1978
	set pppoe max-payload {$mtus[$pid]}
1979

    
1980
EOD;
1981
		}
1982
		if ($type == "pppoe") {
1983
			$mpdconf .= <<<EOD
1984
	set pppoe iface {$port}
1985

    
1986
EOD;
1987
		}
1988

    
1989
		if ($type == "pptp" || $type == "l2tp") {
1990
			$mpdconf .= <<<EOD
1991
	set {$type} self {$localips[$pid]}
1992
	set {$type} peer {$gateways[$pid]}
1993

    
1994
EOD;
1995
		}
1996

    
1997
		$mpdconf .= "\topen\n";
1998
	} //end foreach ($port)
1999

    
2000

    
2001
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2002
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2003
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2004
	} else {
2005
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2006
		if (!$fd) {
2007
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2008
			return 0;
2009
		}
2010
		// Write out mpd_ppp.conf
2011
		fwrite($fd, $mpdconf);
2012
		fclose($fd);
2013
		unset($mpdconf);
2014
	}
2015

    
2016
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2017
	if (isset($ppp['uptime'])) {
2018
		if (!file_exists("/conf/{$pppif}.log")) {
2019
			file_put_contents("/conf/{$pppif}.log", '');
2020
		}
2021
	} else {
2022
		if (file_exists("/conf/{$pppif}.log")) {
2023
			@unlink("/conf/{$pppif}.log");
2024
		}
2025
	}
2026

    
2027
	/* clean up old lock files */
2028
	foreach ($ports as $port) {
2029
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2030
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2031
		}
2032
	}
2033

    
2034
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2035
	/* random IPv6 interface identifier during boot. More details at */
2036
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2037
	if (platform_booting() && is_array($config['interfaces'])) {
2038
		$count = 0;
2039
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2040
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2041
				$tempaddr[$count]['if'] = $tempiface['if'];
2042
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2043
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2044
				$count++;
2045
			}
2046
			// Maximum /31 is is x.y.z.254/31
2047
			if ($count > 122) {
2048
				break;
2049
			}
2050
		}
2051
		unset($count);
2052
	}
2053

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

    
2059
	// Check for PPPoE periodic reset request
2060
	if ($type == "pppoe") {
2061
		if (!empty($ppp['pppoe-reset-type'])) {
2062
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2063
		} else {
2064
			interface_setup_pppoe_reset_file($ppp['if']);
2065
		}
2066
	}
2067
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2068
	$i = 0;
2069
	while ($i < 3) {
2070
		sleep(10);
2071
		if (does_interface_exist($ppp['if'], true)) {
2072
			break;
2073
		}
2074
		$i++;
2075
	}
2076

    
2077
	/* Remove all temporary bogon IPv4 addresses */
2078
	if (is_array($tempaddr)) {
2079
		foreach ($tempaddr as $tempiface) {
2080
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2081
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2082
			}
2083
		}
2084
		unset ($tempaddr);
2085
	}
2086

    
2087
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2088
	/* We should be able to launch the right version for each modem */
2089
	/* We can also guess the mondev from the manufacturer */
2090
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2091
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2092
	foreach ($ports as $port) {
2093
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2094
			$mondev = substr(basename($port), 0, -1);
2095
			$devlist = glob("/dev/{$mondev}?");
2096
			$mondev = basename(end($devlist));
2097
		}
2098
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2099
			$mondev = substr(basename($port), 0, -1) . "1";
2100
		}
2101
		if ($mondev != '') {
2102
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2103
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2104
		}
2105
	}
2106

    
2107
	return 1;
2108
}
2109

    
2110
function interfaces_sync_setup() {
2111
	global $g, $config;
2112

    
2113
	if (isset($config['system']['developerspew'])) {
2114
		$mt = microtime();
2115
		echo "interfaces_sync_setup() being called $mt\n";
2116
	}
2117

    
2118
	if (platform_booting()) {
2119
		echo gettext("Configuring CARP settings...");
2120
		mute_kernel_msgs();
2121
	}
2122

    
2123
	/* suck in configuration items */
2124
	if ($config['hasync']) {
2125
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2126
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2127
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2128
	} else {
2129
		unset($pfsyncinterface);
2130
		unset($pfsyncenabled);
2131
	}
2132

    
2133
	set_sysctl(array(
2134
		"net.inet.carp.preempt" => "1",
2135
		"net.inet.carp.log" => "1")
2136
	);
2137

    
2138
	if (!empty($pfsyncinterface)) {
2139
		$carp_sync_int = get_real_interface($pfsyncinterface);
2140
	} else {
2141
		unset($carp_sync_int);
2142
	}
2143

    
2144
	/* setup pfsync interface */
2145
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2146
		if (is_ipaddr($pfsyncpeerip)) {
2147
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2148
		} else {
2149
			$syncpeer = "-syncpeer";
2150
		}
2151

    
2152
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2153
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2154

    
2155
		sleep(1);
2156

    
2157
		/* 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
2158
		 * for existing sessions.
2159
		 */
2160
		log_error(gettext("waiting for pfsync..."));
2161
		$i = 0;
2162
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2163
			$i++;
2164
			sleep(1);
2165
		}
2166
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2167
		log_error(gettext("Configuring CARP settings finalize..."));
2168
	} else {
2169
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2170
	}
2171

    
2172
	$carplist = get_configured_vip_list('all', VIP_CARP);
2173
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2174
		set_single_sysctl("net.inet.carp.allow", "1");
2175
	} else {
2176
		set_single_sysctl("net.inet.carp.allow", "0");
2177
	}
2178

    
2179
	if (platform_booting()) {
2180
		unmute_kernel_msgs();
2181
		echo gettext("done.") . "\n";
2182
	}
2183
}
2184

    
2185
function interface_proxyarp_configure($interface = "") {
2186
	global $config, $g;
2187
	if (isset($config['system']['developerspew'])) {
2188
		$mt = microtime();
2189
		echo "interface_proxyarp_configure() being called $mt\n";
2190
	}
2191

    
2192
	/* kill any running choparp */
2193
	if (empty($interface)) {
2194
		killbyname("choparp");
2195
	} else {
2196
		$vipif = get_real_interface($interface);
2197
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2198
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2199
		}
2200
	}
2201

    
2202
	$paa = array();
2203
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2204

    
2205
		/* group by interface */
2206
		foreach ($config['virtualip']['vip'] as $vipent) {
2207
			if ($vipent['mode'] === "proxyarp") {
2208
				if ($vipent['interface']) {
2209
					$proxyif = $vipent['interface'];
2210
				} else {
2211
					$proxyif = "wan";
2212
				}
2213

    
2214
				if (!empty($interface) && $interface != $proxyif) {
2215
					continue;
2216
				}
2217

    
2218
				if (!is_array($paa[$proxyif])) {
2219
					$paa[$proxyif] = array();
2220
				}
2221

    
2222
				$paa[$proxyif][] = $vipent;
2223
			}
2224
		}
2225
	}
2226

    
2227
	if (!empty($interface)) {
2228
		if (is_array($paa[$interface])) {
2229
			$paaifip = get_interface_ip($interface);
2230
			if (!is_ipaddr($paaifip)) {
2231
				return;
2232
			}
2233
			$args = get_real_interface($interface) . " auto";
2234
			foreach ($paa[$interface] as $paent) {
2235
				if (isset($paent['subnet'])) {
2236
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2237
				} else if (isset($paent['range'])) {
2238
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2239
				}
2240
			}
2241
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2242
		}
2243
	} else if (count($paa) > 0) {
2244
		foreach ($paa as $paif => $paents) {
2245
			$paaifip = get_interface_ip($paif);
2246
			if (!is_ipaddr($paaifip)) {
2247
				continue;
2248
			}
2249
			$args = get_real_interface($paif) . " auto";
2250
			foreach ($paents as $paent) {
2251
				if (isset($paent['subnet'])) {
2252
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2253
				} else if (isset($paent['range'])) {
2254
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2255
				}
2256
			}
2257
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2258
		}
2259
	}
2260
}
2261

    
2262
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2263
	global $g, $config;
2264

    
2265
	if (is_array($config['virtualip']['vip'])) {
2266
		foreach ($config['virtualip']['vip'] as $vip) {
2267

    
2268
			$iface = $vip['interface'];
2269
			if (substr($iface, 0, 4) == "_vip")
2270
				$iface = get_configured_vip_interface($vip['interface']);
2271
			if ($iface != $interface)
2272
				continue;
2273
			if ($type == VIP_CARP) {
2274
				if ($vip['mode'] != "carp")
2275
					continue;
2276
			} elseif ($type == VIP_IPALIAS) {
2277
				if ($vip['mode'] != "ipalias")
2278
					continue;
2279
			} else {
2280
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2281
					continue;
2282
			}
2283

    
2284
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2285
				interface_vip_bring_down($vip);
2286
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2287
				interface_vip_bring_down($vip);
2288
			else if ($inet == "all")
2289
				interface_vip_bring_down($vip);
2290
		}
2291
	}
2292
}
2293

    
2294
function interfaces_vips_configure($interface = "") {
2295
	global $g, $config;
2296
	if (isset($config['system']['developerspew'])) {
2297
		$mt = microtime();
2298
		echo "interfaces_vips_configure() being called $mt\n";
2299
	}
2300
	$paa = array();
2301
	if (is_array($config['virtualip']['vip'])) {
2302
		$carp_setuped = false;
2303
		$anyproxyarp = false;
2304
		foreach ($config['virtualip']['vip'] as $vip) {
2305
			switch ($vip['mode']) {
2306
				case "proxyarp":
2307
					/* nothing it is handled on interface_proxyarp_configure() */
2308
					if ($interface <> "" && $vip['interface'] <> $interface) {
2309
						continue;
2310
					}
2311
					$anyproxyarp = true;
2312
					break;
2313
				case "ipalias":
2314
					$iface = $vip['interface'];
2315
					if (substr($iface, 0, 4) == "_vip")
2316
						$iface = get_configured_vip_interface($vip['interface']);
2317
					if ($interface <> "" && $iface <> $interface) {
2318
						continue;
2319
					}
2320
					interface_ipalias_configure($vip);
2321
					break;
2322
				case "carp":
2323
					if ($interface <> "" && $vip['interface'] <> $interface) {
2324
						continue;
2325
					}
2326
					if ($carp_setuped == false) {
2327
						$carp_setuped = true;
2328
					}
2329
					interface_carp_configure($vip);
2330
					break;
2331
			}
2332
		}
2333
		if ($carp_setuped == true) {
2334
			interfaces_sync_setup();
2335
		}
2336
		if ($anyproxyarp == true) {
2337
			interface_proxyarp_configure();
2338
		}
2339
	}
2340
}
2341

    
2342
function interface_ipalias_configure(&$vip) {
2343
	global $config;
2344

    
2345
	if ($vip['mode'] != 'ipalias') {
2346
		return;
2347
	}
2348

    
2349
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2350
	if ($realif != "lo0") {
2351
		$if = convert_real_interface_to_friendly_interface_name($realif);
2352
		if (!isset($config['interfaces'][$if])) {
2353
			return;
2354
		}
2355

    
2356
		if (!isset($config['interfaces'][$if]['enable'])) {
2357
			return;
2358
		}
2359
	}
2360

    
2361
	$af = 'inet';
2362
	if (is_ipaddrv6($vip['subnet'])) {
2363
		$af = 'inet6';
2364
	}
2365
	$iface = $vip['interface'];
2366
	$vhid = '';
2367
	if (substr($vip['interface'], 0, 4) == "_vip") {
2368
		$carpvip = get_configured_vip($vip['interface']);
2369
		$iface = $carpvip['interface'];
2370
		$vhid = "vhid {$carpvip['vhid']}";
2371
	}
2372
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2373
	unset($iface, $af, $realif, $carpvip, $vhid);
2374
}
2375

    
2376
function interface_carp_configure(&$vip) {
2377
	global $config, $g;
2378
	if (isset($config['system']['developerspew'])) {
2379
		$mt = microtime();
2380
		echo "interface_carp_configure() being called $mt\n";
2381
	}
2382

    
2383
	if ($vip['mode'] != "carp") {
2384
		return;
2385
	}
2386

    
2387
	/* NOTE: Maybe its useless nowadays */
2388
	$realif = get_real_interface($vip['interface']);
2389
	if (!does_interface_exist($realif)) {
2390
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2391
		return;
2392
	}
2393

    
2394
	$vip_password = $vip['password'];
2395
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2396
	if ($vip['password'] != "") {
2397
		$password = " pass {$vip_password}";
2398
	}
2399

    
2400
	$advbase = "";
2401
	if (!empty($vip['advbase'])) {
2402
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2403
	}
2404

    
2405
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2406
	if ($carp_maintenancemode) {
2407
		$advskew = "advskew 254";
2408
	} else {
2409
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2410
	}
2411

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

    
2414
	if (is_ipaddrv4($vip['subnet'])) {
2415
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2416
	} else if (is_ipaddrv6($vip['subnet'])) {
2417
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2418
	}
2419

    
2420
	return $realif;
2421
}
2422

    
2423
function interface_wireless_clone($realif, $wlcfg) {
2424
	global $config, $g;
2425
	/*   Check to see if interface has been cloned as of yet.
2426
	 *   If it has not been cloned then go ahead and clone it.
2427
	 */
2428
	$needs_clone = false;
2429
	if (is_array($wlcfg['wireless'])) {
2430
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2431
	} else {
2432
		$wlcfg_mode = $wlcfg['mode'];
2433
	}
2434
	switch ($wlcfg_mode) {
2435
		case "hostap":
2436
			$mode = "wlanmode hostap";
2437
			break;
2438
		case "adhoc":
2439
			$mode = "wlanmode adhoc";
2440
			break;
2441
		default:
2442
			$mode = "";
2443
			break;
2444
	}
2445
	$baseif = interface_get_wireless_base($wlcfg['if']);
2446
	if (does_interface_exist($realif)) {
2447
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2448
		$ifconfig_str = implode($output);
2449
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2450
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2451
			$needs_clone = true;
2452
		}
2453
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2454
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2455
			$needs_clone = true;
2456
		}
2457
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2458
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2459
			$needs_clone = true;
2460
		}
2461
	} else {
2462
		$needs_clone = true;
2463
	}
2464

    
2465
	if ($needs_clone == true) {
2466
		/* remove previous instance if it exists */
2467
		if (does_interface_exist($realif)) {
2468
			pfSense_interface_destroy($realif);
2469
		}
2470

    
2471
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2472
		// Create the new wlan interface. FreeBSD returns the new interface name.
2473
		// example:  wlan2
2474
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2475
		if ($ret <> 0) {
2476
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2477
			return false;
2478
		}
2479
		$newif = trim($out[0]);
2480
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2481
		pfSense_interface_rename($newif, $realif);
2482
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2483
	}
2484
	return true;
2485
}
2486

    
2487
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2488
	global $config, $g;
2489

    
2490
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2491
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2492
				 'regdomain', 'regcountry', 'reglocation');
2493

    
2494
	if (!is_interface_wireless($ifcfg['if'])) {
2495
		return;
2496
	}
2497

    
2498
	$baseif = interface_get_wireless_base($ifcfg['if']);
2499

    
2500
	// Sync shared settings for assigned clones
2501
	$iflist = get_configured_interface_list(false, true);
2502
	foreach ($iflist as $if) {
2503
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2504
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2505
				foreach ($shared_settings as $setting) {
2506
					if ($sync_changes) {
2507
						if (isset($ifcfg['wireless'][$setting])) {
2508
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2509
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2510
							unset($config['interfaces'][$if]['wireless'][$setting]);
2511
						}
2512
					} else {
2513
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2514
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2515
						} else if (isset($ifcfg['wireless'][$setting])) {
2516
							unset($ifcfg['wireless'][$setting]);
2517
						}
2518
					}
2519
				}
2520
				if (!$sync_changes) {
2521
					break;
2522
				}
2523
			}
2524
		}
2525
	}
2526

    
2527
	// Read or write settings at shared area
2528
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2529
		foreach ($shared_settings as $setting) {
2530
			if ($sync_changes) {
2531
				if (isset($ifcfg['wireless'][$setting])) {
2532
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2533
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2534
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2535
				}
2536
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2537
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2538
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2539
				} else if (isset($ifcfg['wireless'][$setting])) {
2540
					unset($ifcfg['wireless'][$setting]);
2541
				}
2542
			}
2543
		}
2544
	}
2545

    
2546
	// Sync the mode on the clone creation page with the configured mode on the interface
2547
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2548
		foreach ($config['wireless']['clone'] as &$clone) {
2549
			if ($clone['cloneif'] == $ifcfg['if']) {
2550
				if ($sync_changes) {
2551
					$clone['mode'] = $ifcfg['wireless']['mode'];
2552
				} else {
2553
					$ifcfg['wireless']['mode'] = $clone['mode'];
2554
				}
2555
				break;
2556
			}
2557
		}
2558
		unset($clone);
2559
	}
2560
}
2561

    
2562
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2563
	global $config, $g;
2564

    
2565
	/*    open up a shell script that will be used to output the commands.
2566
	 *    since wireless is changing a lot, these series of commands are fragile
2567
	 *    and will sometimes need to be verified by a operator by executing the command
2568
	 *    and returning the output of the command to the developers for inspection.  please
2569
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2570
	 */
2571

    
2572
	// Remove script file
2573
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2574

    
2575
	// Clone wireless nic if needed.
2576
	interface_wireless_clone($if, $wl);
2577

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

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

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

    
2587
	/* set values for /path/program */
2588
	$hostapd = "/usr/sbin/hostapd";
2589
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2590
	$ifconfig = "/sbin/ifconfig";
2591
	$sysctl = "/sbin/sysctl";
2592
	$killall = "/usr/bin/killall";
2593

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

    
2596
	$wlcmd = array();
2597
	$wl_sysctl = array();
2598
	/* Set a/b/g standard */
2599
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2600
	/* skip mode entirely for "auto" */
2601
	if ($wlcfg['standard'] != "auto") {
2602
		$wlcmd[] = "mode " . escapeshellarg($standard);
2603
	}
2604

    
2605
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2606
	 * to prevent massive packet loss under certain conditions. */
2607
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2608
		$wlcmd[] = "-ampdu";
2609
	}
2610

    
2611
	/* Set ssid */
2612
	if ($wlcfg['ssid']) {
2613
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2614
	}
2615

    
2616
	/* Set 802.11g protection mode */
2617
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2618

    
2619
	/* set wireless channel value */
2620
	if (isset($wlcfg['channel'])) {
2621
		if ($wlcfg['channel'] == "0") {
2622
			$wlcmd[] = "channel any";
2623
		} else {
2624
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2625
		}
2626
	}
2627

    
2628
	/* Set antenna diversity value */
2629
	if (isset($wlcfg['diversity'])) {
2630
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2631
	}
2632

    
2633
	/* Set txantenna value */
2634
	if (isset($wlcfg['txantenna'])) {
2635
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2636
	}
2637

    
2638
	/* Set rxantenna value */
2639
	if (isset($wlcfg['rxantenna'])) {
2640
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2641
	}
2642

    
2643
	/* set Distance value */
2644
	if ($wlcfg['distance']) {
2645
		$distance = escapeshellarg($wlcfg['distance']);
2646
	}
2647

    
2648
	/* Set wireless hostap mode */
2649
	if ($wlcfg['mode'] == "hostap") {
2650
		$wlcmd[] = "mediaopt hostap";
2651
	} else {
2652
		$wlcmd[] = "-mediaopt hostap";
2653
	}
2654

    
2655
	/* Set wireless adhoc mode */
2656
	if ($wlcfg['mode'] == "adhoc") {
2657
		$wlcmd[] = "mediaopt adhoc";
2658
	} else {
2659
		$wlcmd[] = "-mediaopt adhoc";
2660
	}
2661

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

    
2664
	/* handle hide ssid option */
2665
	if (isset($wlcfg['hidessid']['enable'])) {
2666
		$wlcmd[] = "hidessid";
2667
	} else {
2668
		$wlcmd[] = "-hidessid";
2669
	}
2670

    
2671
	/* handle pureg (802.11g) only option */
2672
	if (isset($wlcfg['pureg']['enable'])) {
2673
		$wlcmd[] = "mode 11g pureg";
2674
	} else {
2675
		$wlcmd[] = "-pureg";
2676
	}
2677

    
2678
	/* handle puren (802.11n) only option */
2679
	if (isset($wlcfg['puren']['enable'])) {
2680
		$wlcmd[] = "puren";
2681
	} else {
2682
		$wlcmd[] = "-puren";
2683
	}
2684

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

    
2692
	/* handle turbo option */
2693
	if (isset($wlcfg['turbo']['enable'])) {
2694
		$wlcmd[] = "mediaopt turbo";
2695
	} else {
2696
		$wlcmd[] = "-mediaopt turbo";
2697
	}
2698

    
2699
	/* handle txpower setting */
2700
	// or don't. this has issues at the moment.
2701
	/*
2702
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2703
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2704
	}*/
2705

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

    
2713
	/* Enable wpa if it's configured. No WEP support anymore. */
2714
	if (isset($wlcfg['wpa']['enable'])) {
2715
		$wlcmd[] = "authmode wpa wepmode off ";
2716
	} else {
2717
		$wlcmd[] = "authmode open wepmode off ";
2718
	}
2719

    
2720
	kill_hostapd($if);
2721
	mwexec(kill_wpasupplicant("{$if}"));
2722

    
2723
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2724

    
2725
	switch ($wlcfg['mode']) {
2726
		case 'bss':
2727
			if (isset($wlcfg['wpa']['enable'])) {
2728
				$wpa .= <<<EOD
2729
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2730
ctrl_interface_group=0
2731
ap_scan=1
2732
#fast_reauth=1
2733
network={
2734
ssid="{$wlcfg['ssid']}"
2735
scan_ssid=1
2736
priority=5
2737
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2738
psk="{$wlcfg['wpa']['passphrase']}"
2739
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2740
group={$wlcfg['wpa']['wpa_pairwise']}
2741
}
2742
EOD;
2743

    
2744
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2745
				unset($wpa);
2746
			}
2747
			break;
2748
		case 'hostap':
2749
			if (!empty($wlcfg['wpa']['passphrase'])) {
2750
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2751
			} else {
2752
				$wpa_passphrase = "";
2753
			}
2754
			if (isset($wlcfg['wpa']['enable'])) {
2755
				$wpa .= <<<EOD
2756
interface={$if}
2757
driver=bsd
2758
logger_syslog=-1
2759
logger_syslog_level=0
2760
logger_stdout=-1
2761
logger_stdout_level=0
2762
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2763
ctrl_interface={$g['varrun_path']}/hostapd
2764
ctrl_interface_group=wheel
2765
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2766
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2767
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2768
ssid={$wlcfg['ssid']}
2769
debug={$wlcfg['wpa']['debug_mode']}
2770
wpa={$wlcfg['wpa']['wpa_mode']}
2771
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2772
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2773
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2774
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2775
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2776
{$wpa_passphrase}
2777

    
2778
EOD;
2779

    
2780
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2781
					$wpa .= <<<EOD
2782
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2783
rsn_preauth=1
2784
rsn_preauth_interfaces={$if}
2785

    
2786
EOD;
2787
				}
2788
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2789
					$wpa .= "ieee8021x=1\n";
2790

    
2791
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2792
						$auth_server_port = "1812";
2793
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2794
							$auth_server_port = intval($wlcfg['auth_server_port']);
2795
						}
2796
						$wpa .= <<<EOD
2797

    
2798
auth_server_addr={$wlcfg['auth_server_addr']}
2799
auth_server_port={$auth_server_port}
2800
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2801

    
2802
EOD;
2803
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2804
							$auth_server_port2 = "1812";
2805
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2806
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2807
							}
2808

    
2809
							$wpa .= <<<EOD
2810
auth_server_addr={$wlcfg['auth_server_addr2']}
2811
auth_server_port={$auth_server_port2}
2812
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2813

    
2814
EOD;
2815
						}
2816
					}
2817
				}
2818

    
2819
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2820
				unset($wpa);
2821
			}
2822
			break;
2823
	}
2824

    
2825
	/*
2826
	 *    all variables are set, lets start up everything
2827
	 */
2828

    
2829
	$baseif = interface_get_wireless_base($if);
2830
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2831
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2832

    
2833
	/* set sysctls for the wireless interface */
2834
	if (!empty($wl_sysctl)) {
2835
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2836
		foreach ($wl_sysctl as $wl_sysctl_line) {
2837
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2838
		}
2839
	}
2840

    
2841
	/* set ack timers according to users preference (if he/she has any) */
2842
	if ($distance) {
2843
		fwrite($fd_set, "# Enable ATH distance settings\n");
2844
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2845
	}
2846

    
2847
	if (isset($wlcfg['wpa']['enable'])) {
2848
		if ($wlcfg['mode'] == "bss") {
2849
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2850
		}
2851
		if ($wlcfg['mode'] == "hostap") {
2852
			/* add line to script to restore old mac to make hostapd happy */
2853
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2854
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2855
				$if_curmac = get_interface_mac($if);
2856
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
2857
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2858
						" link " . escapeshellarg($if_oldmac) . "\n");
2859
				}
2860
			}
2861

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

    
2864
			/* add line to script to restore spoofed mac after running hostapd */
2865
			if ($wl['spoofmac']) {
2866
				$if_curmac = get_interface_mac($if);
2867
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
2868
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2869
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
2870
				}
2871
			}
2872
		}
2873
	}
2874

    
2875
	fclose($fd_set);
2876

    
2877
	/* Making sure regulatory settings have actually changed
2878
	 * before applying, because changing them requires bringing
2879
	 * down all wireless networks on the interface. */
2880
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2881
	$ifconfig_str = implode($output);
2882
	unset($output);
2883
	$reg_changing = false;
2884

    
2885
	/* special case for the debug country code */
2886
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2887
		$reg_changing = true;
2888
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2889
		$reg_changing = true;
2890
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2891
		$reg_changing = true;
2892
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2893
		$reg_changing = true;
2894
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2895
		$reg_changing = true;
2896
	}
2897

    
2898
	if ($reg_changing) {
2899
		/* set regulatory domain */
2900
		if ($wlcfg['regdomain']) {
2901
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2902
		}
2903

    
2904
		/* set country */
2905
		if ($wlcfg['regcountry']) {
2906
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2907
		}
2908

    
2909
		/* set location */
2910
		if ($wlcfg['reglocation']) {
2911
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2912
		}
2913

    
2914
		$wlregcmd_args = implode(" ", $wlregcmd);
2915

    
2916
		/* build a complete list of the wireless clones for this interface */
2917
		$clone_list = array();
2918
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2919
			$clone_list[] = interface_get_wireless_clone($baseif);
2920
		}
2921
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2922
			foreach ($config['wireless']['clone'] as $clone) {
2923
				if ($clone['if'] == $baseif) {
2924
					$clone_list[] = $clone['cloneif'];
2925
				}
2926
			}
2927
		}
2928

    
2929
		/* find which clones are up and bring them down */
2930
		$clones_up = array();
2931
		foreach ($clone_list as $clone_if) {
2932
			$clone_status = pfSense_get_interface_addresses($clone_if);
2933
			if ($clone_status['status'] == 'up') {
2934
				$clones_up[] = $clone_if;
2935
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2936
			}
2937
		}
2938

    
2939
		/* apply the regulatory settings */
2940
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2941
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2942

    
2943
		/* bring the clones back up that were previously up */
2944
		foreach ($clones_up as $clone_if) {
2945
			interfaces_bring_up($clone_if);
2946

    
2947
			/*
2948
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2949
			 * is in infrastructure mode, and WPA is enabled.
2950
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2951
			 */
2952
			if ($clone_if != $if) {
2953
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2954
				if ((!empty($friendly_if)) &&
2955
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2956
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2957
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2958
				}
2959
			}
2960
		}
2961
	}
2962

    
2963
	/* The mode must be specified in a separate command before ifconfig
2964
	 * will allow the mode and channel at the same time in the next.
2965
	 * Only do this for AP mode as this breaks client mode (PR 198680).
2966
	 */
2967
	if ($wlcfg['mode'] == "hostap") {
2968
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2969
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2970
	}
2971

    
2972
	/* configure wireless */
2973
	$wlcmd_args = implode(" ", $wlcmd);
2974
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2975
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2976
	/* Bring the interface up only after setting up all the other parameters. */
2977
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
2978
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
2979
	fclose($wlan_setup_log);
2980

    
2981
	unset($wlcmd_args, $wlcmd);
2982

    
2983

    
2984
	sleep(1);
2985
	/* execute hostapd and wpa_supplicant if required in shell */
2986
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2987

    
2988
	return 0;
2989

    
2990
}
2991

    
2992
function kill_hostapd($interface) {
2993
	global $g;
2994

    
2995
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2996
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2997
	}
2998
}
2999

    
3000
function kill_wpasupplicant($interface) {
3001
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3002
}
3003

    
3004
function find_dhclient_process($interface) {
3005
	if ($interface) {
3006
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3007
	} else {
3008
		$pid = 0;
3009
	}
3010

    
3011
	return intval($pid);
3012
}
3013

    
3014
function kill_dhclient_process($interface) {
3015
	if (empty($interface) || !does_interface_exist($interface)) {
3016
		return;
3017
	}
3018

    
3019
	$i = 0;
3020
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3021
		/* 3rd time make it die for sure */
3022
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3023
		posix_kill($pid, $sig);
3024
		sleep(1);
3025
		$i++;
3026
	}
3027
	unset($i);
3028
}
3029

    
3030
function find_dhcp6c_process($interface) {
3031
	global $g;
3032

    
3033
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3034
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3035
	} else {
3036
		return(false);
3037
	}
3038

    
3039
	return intval($pid);
3040
}
3041

    
3042
function kill_dhcp6client_process($interface) {
3043
	if (empty($interface) || !does_interface_exist($interface)) {
3044
		return;
3045
	}
3046

    
3047
	if (($pid = find_dhcp6c_process($interface)) != 0) {
3048
		mwexec("kill -9 {$pid}");
3049
		sleep(1);
3050
	}
3051
}
3052

    
3053
function interface_virtual_create($interface) {
3054
	global $config;
3055

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

    
3095
function interface_vlan_mtu_configured($iface) {
3096
	global $config;
3097

    
3098
	$mtu = 0;
3099
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3100
		foreach ($config['vlans']['vlan'] as $vlan) {
3101

    
3102
			if ($vlan['vlanif'] != $iface)
3103
				continue;
3104

    
3105
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3106
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3107
				/* VLAN MTU */
3108
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3109
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3110
				/* Parent MTU */
3111
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3112
			}
3113
		}
3114
	}
3115

    
3116
	return $mtu;
3117
}
3118

    
3119
function interface_mtu_wanted_for_pppoe($realif) {
3120
	global $config;
3121

    
3122
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3123
		return 0;
3124

    
3125
	$mtu = 0;
3126
	foreach ($config['ppps']['ppp'] as $ppp) {
3127
		if ($ppp['type'] != "pppoe") {
3128
			continue;
3129
		}
3130

    
3131
		$mtus = array();
3132
		if (!empty($ppp['mtu'])) {
3133
			$mtus = explode(',', $ppp['mtu']);
3134
		}
3135
		$ports = explode(',', $ppp['ports']);
3136

    
3137
		foreach ($ports as $pid => $port) {
3138
			$parentifa = get_parent_interface($port);
3139
			$parentif = $parentifa[0];
3140
			if ($parentif != $realif)
3141
				continue;
3142

    
3143
			// there is an MTU configured on the port in question
3144
			if (!empty($mtus[$pid])) {
3145
				$mtu = intval($mtus[$pid]) + 8;
3146
			// or use the MTU configured on the interface ...
3147
			} elseif (is_array($config['interfaces'])) {
3148
				foreach ($config['interfaces'] as $interface) {
3149
					if ($interface['if'] == $ppp['if'] &&
3150
					    !empty($interface['mtu'])) {
3151
						$mtu = intval($interface['mtu']) + 8;
3152
						break;
3153
					}
3154
				}
3155
			}
3156
		}
3157
	}
3158

    
3159
	return $mtu;
3160
}
3161

    
3162
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3163
	global $config, $g;
3164
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3165
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3166

    
3167
	$wancfg = $config['interfaces'][$interface];
3168

    
3169
	if (!isset($wancfg['enable'])) {
3170
		return;
3171
	}
3172

    
3173
	$realif = get_real_interface($interface);
3174
	$realhwif_array = get_parent_interface($interface);
3175
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3176
	$realhwif = $realhwif_array[0];
3177

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

    
3199
		/* only bring down the interface when both v4 and v6 are set to NONE */
3200
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3201
			interface_bring_down($interface);
3202
		}
3203
	}
3204

    
3205
	$interface_to_check = $realif;
3206
	if (interface_isppp_type($interface)) {
3207
		$interface_to_check = $realhwif;
3208
	}
3209

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

    
3215
	/* Disable Accepting router advertisements unless specifically requested */
3216
	if ($g['debug']) {
3217
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3218
	}
3219
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3220

    
3221
	/* wireless configuration? */
3222
	if (is_array($wancfg['wireless'])) {
3223
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3224
	}
3225

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

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

    
3252
	/* media */
3253
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3254
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3255
		if ($wancfg['media']) {
3256
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3257
		}
3258
		if ($wancfg['mediaopt']) {
3259
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3260
		}
3261
		mwexec($cmd);
3262
	}
3263

    
3264
	/* Apply hw offloading policies as configured */
3265
	enable_hardware_offloading($interface);
3266

    
3267
	/* invalidate interface/ip/sn cache */
3268
	get_interface_arr(true);
3269
	unset($interface_ip_arr_cache[$realif]);
3270
	unset($interface_sn_arr_cache[$realif]);
3271
	unset($interface_ipv6_arr_cache[$realif]);
3272
	unset($interface_snv6_arr_cache[$realif]);
3273

    
3274
	$tunnelif = substr($realif, 0, 3);
3275

    
3276
	$mtuif = $realif;
3277
	$mtuhwif = $realhwif;
3278

    
3279
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3280
	if (interface_isppp_type($interface)) {
3281
		$mtuif = $realhwif;
3282
		$mtuhwif_array = get_parent_interface($mtuif);
3283
		$mtuhwif = $mtuhwif_array[0];
3284
	}
3285

    
3286
	$wantedmtu = 0;
3287
	if (is_array($config['interfaces'])) {
3288
		foreach ($config['interfaces'] as $tmpinterface) {
3289
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3290
				$wantedmtu = $tmpinterface['mtu'];
3291
				break;
3292
			}
3293
		}
3294
	}
3295

    
3296
	/* MTU is not specified for interface, try the pppoe settings. */
3297
	if ($wantedmtu == 0) {
3298
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3299
	}
3300
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3301
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3302
	}
3303

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

    
3309
	if (stristr($mtuif, "_vlan")) {
3310
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3311
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3312
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3313
			if ($wancfg['mtu'] > $parentmtu) {
3314
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3315
			}
3316
		}
3317

    
3318
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3319

    
3320
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3321
			$configuredmtu = $parentmtu;
3322
		if ($configuredmtu != 0)
3323
			$mtu = $configuredmtu;
3324
		else
3325
			$mtu = $wantedmtu;
3326

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

    
3352
	if (does_interface_exist($wancfg['if'])) {
3353
		interfaces_bring_up($wancfg['if']);
3354
	}
3355

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

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

    
3407
	interface_netgraph_needed($interface);
3408

    
3409
	if (!platform_booting()) {
3410
		link_interface_to_vips($interface, "update");
3411

    
3412
		if ($tunnelif != 'gre') {
3413
			unset($gre);
3414
			$gre = link_interface_to_gre($interface);
3415
			if (!empty($gre)) {
3416
				array_walk($gre, 'interface_gre_configure');
3417
			}
3418
		}
3419

    
3420
		if ($tunnelif != 'gif') {
3421
			unset($gif);
3422
			$gif = link_interface_to_gif ($interface);
3423
			if (!empty($gif)) {
3424
				array_walk($gif, 'interface_gif_configure');
3425
			}
3426
		}
3427

    
3428
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3429
			unset($bridgetmp);
3430
			$bridgetmp = link_interface_to_bridge($interface);
3431
			if (!empty($bridgetmp)) {
3432
				interface_bridge_add_member($bridgetmp, $realif);
3433
			}
3434
		}
3435

    
3436
		$grouptmp = link_interface_to_group($interface);
3437
		if (!empty($grouptmp)) {
3438
			array_walk($grouptmp, 'interface_group_add_member');
3439
		}
3440

    
3441
		if ($interface == "lan") {
3442
			/* make new hosts file */
3443
			system_hosts_generate();
3444
		}
3445

    
3446
		if ($reloadall == true) {
3447

    
3448
			/* reconfigure static routes (kernel may have deleted them) */
3449
			system_routing_configure($interface);
3450

    
3451
			/* reload ipsec tunnels */
3452
			send_event("service reload ipsecdns");
3453

    
3454
			if (isset($config['dnsmasq']['enable'])) {
3455
				services_dnsmasq_configure();
3456
			}
3457

    
3458
			if (isset($config['unbound']['enable'])) {
3459
				services_unbound_configure();
3460
			}
3461

    
3462
			/* update dyndns */
3463
			send_event("service reload dyndns {$interface}");
3464

    
3465
			/* reload captive portal */
3466
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3467
				require_once('captiveportal.inc');
3468
			}
3469
			captiveportal_init_rules_byinterface($interface);
3470
		}
3471
	}
3472

    
3473
	interfaces_staticarp_configure($interface);
3474
	return 0;
3475
}
3476

    
3477
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3478
	global $config, $g;
3479

    
3480
	if (!is_array($wancfg)) {
3481
		return;
3482
	}
3483

    
3484
	if (!isset($wancfg['enable'])) {
3485
		return;
3486
	}
3487

    
3488
	/* If the interface is not configured via another, exit */
3489
	if (empty($wancfg['track6-interface'])) {
3490
		return;
3491
	}
3492

    
3493
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3494
	$realif = get_real_interface($interface);
3495
	$linklocal = find_interface_ipv6_ll($realif, true);
3496
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3497
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3498
	}
3499
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3500
	/* XXX: Probably should remove? */
3501
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3502

    
3503
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3504
	if (!isset($trackcfg['enable'])) {
3505
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3506
		return;
3507
	}
3508

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

    
3539
	if ($linkupevent == false && !platform_booting()) {
3540
		if (!function_exists('services_dhcpd_configure')) {
3541
			require_once("services.inc");
3542
		}
3543

    
3544
		/* restart dns servers (defering dhcpd reload) */
3545
		if (isset($config['unbound']['enable'])) {
3546
			services_unbound_configure(false);
3547
		}
3548
		if (isset($config['dnsmasq']['enable'])) {
3549
			services_dnsmasq_configure(false);
3550
		}
3551

    
3552
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3553
		services_dhcpd_configure("inet6");
3554
	}
3555

    
3556
	return 0;
3557
}
3558

    
3559
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3560
	global $config, $g;
3561
	global $interface_ipv6_arr_cache;
3562
	global $interface_snv6_arr_cache;
3563

    
3564
	if (!is_array($lancfg)) {
3565
		return;
3566
	}
3567

    
3568
	/* If the interface is not configured via another, exit */
3569
	if (empty($lancfg['track6-interface'])) {
3570
		return;
3571
	}
3572

    
3573
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3574
	if (empty($wancfg)) {
3575
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3576
		return;
3577
	}
3578

    
3579
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3580
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3581
		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']));
3582
		return;
3583
	}
3584
	$hexwanv4 = return_hex_ipv4($ip4address);
3585

    
3586
	/* create the long prefix notation for math, save the prefix length */
3587
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3588
	$rd6prefixlen = $rd6prefix[1];
3589
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3590

    
3591
	/* binary presentation of the prefix for all 128 bits. */
3592
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3593

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

    
3599
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3600
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3601
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3602
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3603
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3604
	/* fill the rest out with zeros */
3605
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3606

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

    
3610
	$lanif = get_real_interface($interface);
3611
	$oip = find_interface_ipv6($lanif);
3612
	if (is_ipaddrv6($oip)) {
3613
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3614
	}
3615
	unset($interface_ipv6_arr_cache[$lanif]);
3616
	unset($interface_snv6_arr_cache[$lanif]);
3617
	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));
3618
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3619

    
3620
	return 0;
3621
}
3622

    
3623
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3624
	global $config, $g;
3625
	global $interface_ipv6_arr_cache;
3626
	global $interface_snv6_arr_cache;
3627

    
3628
	if (!is_array($lancfg)) {
3629
		return;
3630
	}
3631

    
3632
	/* If the interface is not configured via another, exit */
3633
	if (empty($lancfg['track6-interface'])) {
3634
		return;
3635
	}
3636

    
3637
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3638
	if (empty($wancfg)) {
3639
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3640
		return;
3641
	}
3642

    
3643
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3644
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3645
		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']));
3646
		return;
3647
	}
3648
	$hexwanv4 = return_hex_ipv4($ip4address);
3649

    
3650
	/* create the long prefix notation for math, save the prefix length */
3651
	$sixto4prefix = "2002::";
3652
	$sixto4prefixlen = 16;
3653
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3654

    
3655
	/* binary presentation of the prefix for all 128 bits. */
3656
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3657

    
3658
	/* just save the left prefix length bits */
3659
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3660
	/* add the v4 address */
3661
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3662
	/* add the custom prefix id */
3663
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3664
	/* fill the rest out with zeros */
3665
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3666

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

    
3670
	$lanif = get_real_interface($interface);
3671
	$oip = find_interface_ipv6($lanif);
3672
	if (is_ipaddrv6($oip)) {
3673
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3674
	}
3675
	unset($interface_ipv6_arr_cache[$lanif]);
3676
	unset($interface_snv6_arr_cache[$lanif]);
3677
	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));
3678
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3679

    
3680
	return 0;
3681
}
3682

    
3683
function interface_6rd_configure($interface = "wan", $wancfg) {
3684
	global $config, $g;
3685

    
3686
	/* because this is a tunnel interface we can only function
3687
	 *	with a public IPv4 address on the interface */
3688

    
3689
	if (!is_array($wancfg)) {
3690
		return;
3691
	}
3692

    
3693
	if (!is_module_loaded('if_stf.ko')) {
3694
		mwexec('/sbin/kldload if_stf.ko');
3695
	}
3696

    
3697
	$wanif = get_real_interface($interface);
3698
	$ip4address = find_interface_ip($wanif);
3699
	if (!is_ipaddrv4($ip4address)) {
3700
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3701
		return false;
3702
	}
3703
	$hexwanv4 = return_hex_ipv4($ip4address);
3704

    
3705
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3706
		$wancfg['prefix-6rd-v4plen'] = 0;
3707
	}
3708

    
3709
	/* create the long prefix notation for math, save the prefix length */
3710
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3711
	$rd6prefixlen = $rd6prefix[1];
3712
	$brgw = explode('.', $wancfg['gateway-6rd']);
3713
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
3714
	$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);
3715
	if (strlen($rd6brgw) < 128) {
3716
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3717
	}
3718
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
3719
	unset($brgw);
3720
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3721

    
3722
	/* binary presentation of the prefix for all 128 bits. */
3723
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3724

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

    
3732
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3733
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3734

    
3735

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

    
3756
	/* write out a default router file */
3757
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3758
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3759

    
3760
	$ip4gateway = get_interface_gateway($interface);
3761
	if (is_ipaddrv4($ip4gateway)) {
3762
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
3763
	}
3764

    
3765
	/* configure dependent interfaces */
3766
	if (!platform_booting()) {
3767
		link_interface_to_track6($interface, "update");
3768
	}
3769

    
3770
	return 0;
3771
}
3772

    
3773
function interface_6to4_configure($interface = "wan", $wancfg) {
3774
	global $config, $g;
3775

    
3776
	/* because this is a tunnel interface we can only function
3777
	 *	with a public IPv4 address on the interface */
3778

    
3779
	if (!is_array($wancfg)) {
3780
		return;
3781
	}
3782

    
3783
	$wanif = get_real_interface($interface);
3784
	$ip4address = find_interface_ip($wanif);
3785
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3786
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3787
		return false;
3788
	}
3789

    
3790
	/* create the long prefix notation for math, save the prefix length */
3791
	$stfprefixlen = 16;
3792
	$stfprefix = Net_IPv6::uncompress("2002::");
3793
	$stfarr = explode(":", $stfprefix);
3794
	$v4prefixlen = "0";
3795

    
3796
	/* we need the hex form of the interface IPv4 address */
3797
	$ip4arr = explode(".", $ip4address);
3798
	$hexwanv4 = "";
3799
	foreach ($ip4arr as $octet) {
3800
		$hexwanv4 .= sprintf("%02x", $octet);
3801
	}
3802

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

    
3810
	/* binary presentation of the prefix for all 128 bits. */
3811
	$stfprefixbin = "";
3812
	foreach ($stfarr as $element) {
3813
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3814
	}
3815
	/* just save the left prefix length bits */
3816
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3817

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

    
3822
	/* for the local subnet too. */
3823
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3824
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3825

    
3826
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3827
	$stfbrarr = array();
3828
	$stfbrbinarr = array();
3829
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3830
	foreach ($stfbrbinarr as $bin) {
3831
		$stfbrarr[] = dechex(bindec($bin));
3832
	}
3833
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3834

    
3835
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3836
	$stflanarr = array();
3837
	$stflanbinarr = array();
3838
	$stflanbinarr = str_split($stflanbin, 16);
3839
	foreach ($stflanbinarr as $bin) {
3840
		$stflanarr[] = dechex(bindec($bin));
3841
	}
3842
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3843
	$stflanarr[7] = 1;
3844
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3845

    
3846
	/* setup the stf interface */
3847
	if (!is_module_loaded("if_stf")) {
3848
		mwexec("/sbin/kldload if_stf.ko");
3849
	}
3850
	$stfiface = "{$interface}_stf";
3851
	if (does_interface_exist($stfiface)) {
3852
		pfSense_interface_destroy($stfiface);
3853
	}
3854
	$tmpstfiface = pfSense_interface_create("stf");
3855
	pfSense_interface_rename($tmpstfiface, $stfiface);
3856
	pfSense_interface_flags($stfiface, IFF_LINK2);
3857
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3858

    
3859
	if ($g['debug']) {
3860
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3861
	}
3862

    
3863
	/* write out a default router file */
3864
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3865
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3866

    
3867
	$ip4gateway = get_interface_gateway($interface);
3868
	if (is_ipaddrv4($ip4gateway)) {
3869
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
3870
	}
3871

    
3872
	if (!platform_booting()) {
3873
		link_interface_to_track6($interface, "update");
3874
	}
3875

    
3876
	return 0;
3877
}
3878

    
3879
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3880
	global $config, $g;
3881

    
3882
	if (!is_array($wancfg)) {
3883
		return;
3884
	}
3885

    
3886
	$wanif = get_real_interface($interface, "inet6");
3887
	$dhcp6cconf = "";
3888

    
3889
	if (!empty($config['system']['global-v6duid'])) {
3890
		// Write the DUID file
3891
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
3892
		    log_error(gettext("Failed to write user DUID file!"));
3893
		}
3894
	}
3895
	
3896
	if ($wancfg['adv_dhcp6_config_file_override']) {
3897
		// DHCP6 Config File Override
3898
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3899
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3900
		// DHCP6 Config File Advanced
3901
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3902
	} else {
3903
		// DHCP6 Config File Basic
3904
		$dhcp6cconf .= "interface {$wanif} {\n";
3905

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

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

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

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

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

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

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

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

    
3991
	/* non ipoe Process */
3992
	if (!isset($wancfg['dhcp6withoutra'])) {
3993
		$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3994
		$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3995
		$rtsoldscript .= "\t/bin/sleep 1\n";
3996
		$rtsoldscript .= "fi\n";
3997
	} else {
3998
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
3999
		$rtsoldscript .= "/bin/sleep 1\n";
4000
	}
4001
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4002
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4003

    
4004

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

    
4019
	/* accept router advertisements for this interface */
4020
	log_error("Accept router advertisements on interface {$wanif} ");
4021
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4022

    
4023
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4024
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4025
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4026
		sleep(2);
4027
	}
4028

    
4029
	/* start dhcp6c here if we don't want to wait for ra */
4030
	if (isset($wancfg['dhcp6withoutra'])) {
4031
		kill_dhcp6client_process($wanif);
4032

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

    
4038
	/* NOTE: will be called from rtsold invoked script
4039
	 * link_interface_to_track6($interface, "update");
4040
	 */
4041

    
4042
	return 0;
4043
}
4044

    
4045
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4046
	global $g;
4047

    
4048
	$send_options = "";
4049
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4050
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4051
		foreach ($options as $option) {
4052
			$send_options .= "\tsend " . trim($option) . ";\n";
4053
		}
4054
	}
4055

    
4056
	$request_options = "";
4057
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4058
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4059
		foreach ($options as $option) {
4060
			$request_options .= "\trequest " . trim($option) . ";\n";
4061
		}
4062
	}
4063

    
4064
	$information_only = "";
4065
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4066
		$information_only = "\tinformation-only;\n";
4067
	}
4068

    
4069
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4070
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4071
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4072
	}
4073

    
4074
	$interface_statement  = "interface";
4075
	$interface_statement .= " {$wanif}";
4076
	$interface_statement .= " {\n";
4077
	$interface_statement .= "$send_options";
4078
	$interface_statement .= "$request_options";
4079
	$interface_statement .= "$information_only";
4080
	$interface_statement .= "$script";
4081
	$interface_statement .= "};\n";
4082

    
4083
	$id_assoc_statement_address = "";
4084
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4085
		$id_assoc_statement_address .= "id-assoc";
4086
		$id_assoc_statement_address .= " na";
4087
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4088
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4089
		}
4090
		$id_assoc_statement_address .= " { ";
4091

    
4092
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4093
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4094
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4095
			$id_assoc_statement_address .= "\n\taddress";
4096
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4097
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4098
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4099
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4100
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4101
			}
4102
			$id_assoc_statement_address .= ";\n";
4103
		}
4104

    
4105
		$id_assoc_statement_address .= "};\n";
4106
	}
4107

    
4108
	$id_assoc_statement_prefix = "";
4109
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4110
		$id_assoc_statement_prefix .= "id-assoc";
4111
		$id_assoc_statement_prefix .= " pd";
4112
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4113
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4114
		}
4115
		$id_assoc_statement_prefix .= " { ";
4116

    
4117
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4118
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4119
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4120
			$id_assoc_statement_prefix .= "\n\tprefix";
4121
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4122
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4123
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4124
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4125
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4126
			}
4127
			$id_assoc_statement_prefix .= ";";
4128
		}
4129

    
4130
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4131
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4132
			$id_assoc_statement_prefix .= " {$wanif}";
4133
			$id_assoc_statement_prefix .= " {\n";
4134
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4135
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4136
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4137
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4138
			}
4139
			$id_assoc_statement_prefix .= "\t};";
4140
		}
4141

    
4142
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4143
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4144
			$id_assoc_statement_prefix .= "\n";
4145
		}
4146

    
4147
		$id_assoc_statement_prefix .= "};\n";
4148
	}
4149

    
4150
	$authentication_statement = "";
4151
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4152
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4153
		$authentication_statement .= "authentication";
4154
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4155
		$authentication_statement .= " {\n";
4156
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4157
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4158
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4159
		}
4160
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4161
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4162
		}
4163
		$authentication_statement .= "};\n";
4164
	}
4165

    
4166
	$key_info_statement = "";
4167
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4168
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4169
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4170
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4171
		$key_info_statement .= "keyinfo";
4172
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4173
		$key_info_statement .= " {\n";
4174
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4175
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4176
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4177
		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'])) {
4178
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4179
		}
4180
		$key_info_statement .= "};\n";
4181
	}
4182

    
4183
	$dhcp6cconf  = $interface_statement;
4184
	$dhcp6cconf .= $id_assoc_statement_address;
4185
	$dhcp6cconf .= $id_assoc_statement_prefix;
4186
	$dhcp6cconf .= $authentication_statement;
4187
	$dhcp6cconf .= $key_info_statement;
4188

    
4189
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4190

    
4191
	return $dhcp6cconf;
4192
}
4193

    
4194

    
4195
function DHCP6_Config_File_Override($wancfg, $wanif) {
4196

    
4197
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4198

    
4199
	if ($dhcp6cconf === false) {
4200
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4201
		return '';
4202
	} else {
4203
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4204
	}
4205
}
4206

    
4207

    
4208
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4209

    
4210
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4211

    
4212
	return $dhcp6cconf;
4213
}
4214

    
4215

    
4216
function interface_dhcp_configure($interface = "wan") {
4217
	global $config, $g;
4218

    
4219
	$wancfg = $config['interfaces'][$interface];
4220
	$wanif = $wancfg['if'];
4221
	if (empty($wancfg)) {
4222
		$wancfg = array();
4223
	}
4224

    
4225
	/* generate dhclient_wan.conf */
4226
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4227
	if (!$fd) {
4228
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4229
		return 1;
4230
	}
4231

    
4232
	if ($wancfg['dhcphostname']) {
4233
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4234
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4235
	} else {
4236
		$dhclientconf_hostname = "";
4237
	}
4238

    
4239
	$wanif = get_real_interface($interface);
4240
	if (empty($wanif)) {
4241
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4242
		return 0;
4243
	}
4244
	$dhclientconf = "";
4245

    
4246
	$dhclientconf .= <<<EOD
4247
interface "{$wanif}" {
4248
timeout 60;
4249
retry 15;
4250
select-timeout 0;
4251
initial-interval 1;
4252
	{$dhclientconf_hostname}
4253
	script "/usr/local/sbin/pfSense-dhclient-script";
4254
EOD;
4255

    
4256
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4257
		$dhclientconf .= <<<EOD
4258

    
4259
	reject {$wancfg['dhcprejectfrom']};
4260
EOD;
4261
	}
4262
	$dhclientconf .= <<<EOD
4263

    
4264
}
4265

    
4266
EOD;
4267

    
4268
	// DHCP Config File Advanced
4269
	if ($wancfg['adv_dhcp_config_advanced']) {
4270
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4271
	}
4272

    
4273
	if (is_ipaddr($wancfg['alias-address'])) {
4274
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4275
		$dhclientconf .= <<<EOD
4276
alias {
4277
	interface "{$wanif}";
4278
	fixed-address {$wancfg['alias-address']};
4279
	option subnet-mask {$subnetmask};
4280
}
4281

    
4282
EOD;
4283
	}
4284

    
4285
	// DHCP Config File Override
4286
	if ($wancfg['adv_dhcp_config_file_override']) {
4287
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4288
	}
4289

    
4290
	fwrite($fd, $dhclientconf);
4291
	fclose($fd);
4292

    
4293
	/* bring wan interface up before starting dhclient */
4294
	if ($wanif) {
4295
		interfaces_bring_up($wanif);
4296
	} else {
4297
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4298
	}
4299

    
4300
	/* Make sure dhclient is not running */
4301
	kill_dhclient_process($wanif);
4302

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

    
4306
	return 0;
4307
}
4308

    
4309
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4310

    
4311
	$hostname = "";
4312
	if ($wancfg['dhcphostname'] != '') {
4313
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4314
	}
4315

    
4316
	/* DHCP Protocol Timings */
4317
	$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");
4318
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4319
		$pt_variable = "{$Protocol_Timing}";
4320
		${$pt_variable} = "";
4321
		if ($wancfg[$Protocol_Timing] != "") {
4322
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4323
		}
4324
	}
4325

    
4326
	$send_options = "";
4327
	if ($wancfg['adv_dhcp_send_options'] != '') {
4328
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4329
		foreach ($options as $option) {
4330
			$send_options .= "\tsend " . trim($option) . ";\n";
4331
		}
4332
	}
4333

    
4334
	$request_options = "";
4335
	if ($wancfg['adv_dhcp_request_options'] != '') {
4336
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4337
	}
4338

    
4339
	$required_options = "";
4340
	if ($wancfg['adv_dhcp_required_options'] != '') {
4341
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4342
	}
4343

    
4344
	$option_modifiers = "";
4345
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4346
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4347
		foreach ($modifiers as $modifier) {
4348
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4349
		}
4350
	}
4351

    
4352
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4353
	$dhclientconf .= "\n";
4354
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4355
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4356
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4357
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4358
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4359
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4360
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4361
	$dhclientconf .= "\n";
4362
	$dhclientconf .= "# DHCP Protocol Options\n";
4363
	$dhclientconf .= "{$hostname}";
4364
	$dhclientconf .= "{$send_options}";
4365
	$dhclientconf .= "{$request_options}";
4366
	$dhclientconf .= "{$required_options}";
4367
	$dhclientconf .= "{$option_modifiers}";
4368
	$dhclientconf .= "\n";
4369
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4370
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4371
	}
4372
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
4373
	$dhclientconf .= "}\n";
4374

    
4375
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4376

    
4377
	return $dhclientconf;
4378
}
4379

    
4380
function DHCP_Config_Option_Split($option_string) {
4381
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4382
	return $matches ? $matches[0] : [];
4383
}
4384

    
4385
function DHCP_Config_File_Override($wancfg, $wanif) {
4386

    
4387
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4388

    
4389
	if ($dhclientconf === false) {
4390
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading.\n"), $wancfg['adv_dhcp_config_file_override_path']));
4391
		return '';
4392
	} else {
4393
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4394
	}
4395
}
4396

    
4397

    
4398
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4399

    
4400
	/* Apply Interface Substitutions */
4401
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4402

    
4403
	/* Apply Hostname Substitutions */
4404
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4405

    
4406
	/* Arrays of MAC Address Types, Cases, Delimiters */
4407
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4408
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4409
	$various_mac_cases      = array("U", "L");
4410
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4411

    
4412
	/* Apply MAC Address Substitutions */
4413
	foreach ($various_mac_types as $various_mac_type) {
4414
		foreach ($various_mac_cases as $various_mac_case) {
4415
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4416

    
4417
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4418
				if ($res !== false) {
4419

    
4420
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4421
					if ("$various_mac_case" == "U") {
4422
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4423
					}
4424
					if ("$various_mac_case" == "L") {
4425
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4426
					}
4427

    
4428
					if ("$various_mac_type" == "mac_addr_hex") {
4429
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4430
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4431
						$dhcpclientconf_mac_hex = "";
4432
						$delimiter = "";
4433
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4434
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4435
							$delimiter = ":";
4436
						}
4437
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4438
					}
4439

    
4440
					/* MAC Address Delimiter Substitutions */
4441
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4442

    
4443
					/* Apply MAC Address Substitutions */
4444
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4445
				}
4446
			}
4447
		}
4448
	}
4449

    
4450
	return $dhclientconf;
4451
}
4452

    
4453
function interfaces_group_setup() {
4454
	global $config;
4455

    
4456
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4457
		return;
4458
	}
4459

    
4460
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4461
		interface_group_setup($groupar);
4462
	}
4463

    
4464
	return;
4465
}
4466

    
4467
function interface_group_setup(&$groupname /* The parameter is an array */) {
4468
	global $config;
4469

    
4470
	if (!is_array($groupname)) {
4471
		return;
4472
	}
4473
	$members = explode(" ", $groupname['members']);
4474
	foreach ($members as $ifs) {
4475
		$realif = get_real_interface($ifs);
4476
		if ($realif && does_interface_exist($realif)) {
4477
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4478
		}
4479
	}
4480

    
4481
	return;
4482
}
4483

    
4484
function is_interface_group($if) {
4485
	global $config;
4486

    
4487
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4488
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4489
			if ($groupentry['ifname'] === $if) {
4490
				return true;
4491
			}
4492
		}
4493
	}
4494

    
4495
	return false;
4496
}
4497

    
4498
function interface_group_add_member($interface, $groupname) {
4499
	$interface = get_real_interface($interface);
4500
	if (does_interface_exist($interface)) {
4501
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4502
	}
4503
}
4504

    
4505
/* COMPAT Function */
4506
function convert_friendly_interface_to_real_interface_name($interface) {
4507
	return get_real_interface($interface);
4508
}
4509

    
4510
/* COMPAT Function */
4511
function get_real_wan_interface($interface = "wan") {
4512
	return get_real_interface($interface);
4513
}
4514

    
4515
/* COMPAT Function */
4516
function get_current_wan_address($interface = "wan") {
4517
	return get_interface_ip($interface);
4518
}
4519

    
4520
/*
4521
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4522
 */
4523
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4524
	global $config;
4525

    
4526
	/* XXX: For speed reasons reference directly the interface array */
4527
	$ifdescrs = &$config['interfaces'];
4528
	//$ifdescrs = get_configured_interface_list(false, true);
4529

    
4530
	foreach ($ifdescrs as $if => $ifname) {
4531
		if ($if == $interface || $ifname['if'] == $interface) {
4532
			return $if;
4533
		}
4534

    
4535
		if (get_real_interface($if) == $interface) {
4536
			return $if;
4537
		}
4538

    
4539
		if ($checkparent == false) {
4540
			continue;
4541
		}
4542

    
4543
		$int = get_parent_interface($if, true);
4544
		if (is_array($int)) {
4545
			foreach ($int as $iface) {
4546
				if ($iface == $interface) {
4547
					return $if;
4548
				}
4549
			}
4550
		}
4551
	}
4552

    
4553
	if ($interface == "enc0") {
4554
		return 'IPsec';
4555
	}
4556
}
4557

    
4558
/* attempt to resolve interface to friendly descr */
4559
function convert_friendly_interface_to_friendly_descr($interface) {
4560
	global $config;
4561

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

    
4615
	return $ifdesc;
4616
}
4617

    
4618
function convert_real_interface_to_friendly_descr($interface) {
4619

    
4620
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4621

    
4622
	if (!empty($ifdesc)) {
4623
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4624
	}
4625

    
4626
	return $interface;
4627
}
4628

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

    
4641
	$parents = array();
4642
	//Check that we got a valid interface passed
4643
	$realif = get_real_interface($interface);
4644
	if ($realif == NULL) {
4645
		return $parents;
4646
	}
4647

    
4648
	// If we got a real interface, find it's friendly assigned name
4649
	if ($interface == $realif && $avoidrecurse == false) {
4650
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4651
	}
4652

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

    
4692
	if (empty($parents)) {
4693
		// Handle _vlans not assigned to an interface
4694
		if (strpos($realif, '_vlan') !== FALSE) {
4695
			if (is_array($config['vlans']['vlan'])) {
4696
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4697
					if ($realif == $vlan['vlanif']) {
4698
						$parents[0] = $vlan['if'];
4699
						break;
4700
					}
4701
				}
4702
			}
4703
		}
4704
	}
4705

    
4706
	if (empty($parents)) {
4707
		$parents[0] = $realif;
4708
	}
4709

    
4710
	return $parents;
4711
}
4712

    
4713
/*
4714
 *  get_parent_physical_interface($interface):
4715
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4716
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4717
 */
4718
function get_parent_physical_interface($interface) {
4719
	global $config;
4720

    
4721
	$realif = get_parent_interface($interface);
4722

    
4723
	if (substr($realif[0], 0, 4) == "lagg") {
4724
		foreach ($config['laggs']['lagg'] as $lagg) {
4725
			if ($realif[0] == $lagg['laggif']) {
4726
				return explode(",", $lagg['members']);
4727
			}
4728
		}
4729
	} else {
4730
		return $realif;
4731
	}
4732
}
4733

    
4734
function interface_is_wireless_clone($wlif) {
4735
	if (!stristr($wlif, "_wlan")) {
4736
		return false;
4737
	} else {
4738
		return true;
4739
	}
4740
}
4741

    
4742
function interface_get_wireless_base($wlif) {
4743
	if (!stristr($wlif, "_wlan")) {
4744
		return $wlif;
4745
	} else {
4746
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4747
	}
4748
}
4749

    
4750
function interface_get_wireless_clone($wlif) {
4751
	if (!stristr($wlif, "_wlan")) {
4752
		return $wlif . "_wlan0";
4753
	} else {
4754
		return $wlif;
4755
	}
4756
}
4757

    
4758
function interface_list_wireless() {
4759
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
4760

    
4761
	$result = array();
4762
	foreach ($portlist as $port) {
4763
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
4764
			continue;
4765
		}
4766

    
4767
		$desc = $port . " ( " . get_single_sysctl(
4768
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
4769

    
4770
		$result[] = array(
4771
		    "if" => $port,
4772
		    "descr" => $desc
4773
		);
4774
	}
4775

    
4776
	return $result;
4777
}
4778

    
4779
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4780
	global $config, $g;
4781

    
4782
	$wanif = NULL;
4783

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

    
4826
			if (empty($config['interfaces'][$interface])) {
4827
				break;
4828
			}
4829

    
4830
			$cfg = &$config['interfaces'][$interface];
4831

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

    
4888
	return $wanif;
4889
}
4890

    
4891
/* Guess the physical interface by providing a IP address */
4892
function guess_interface_from_ip($ipaddress) {
4893

    
4894
	$family = '';
4895
	if (is_ipaddrv4($ipaddress)) {
4896
		$family = 'inet';
4897
	}
4898
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4899
		$family = 'inet6';
4900
	}
4901

    
4902
	if (empty($family)) {
4903
		return false;
4904
	}
4905

    
4906
	/* create a route table we can search */
4907
	$output = '';
4908
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4909
	$output[0] = trim($output[0], " \n");
4910
	if (!empty($output[0])) {
4911
		return $output[0];
4912
	}
4913

    
4914
	return false;
4915
}
4916

    
4917
/*
4918
 * find_ip_interface($ip): return the interface where an ip is defined
4919
 *   (or if $bits is specified, where an IP within the subnet is defined)
4920
 */
4921
function find_ip_interface($ip, $bits = null) {
4922
	if (!is_ipaddr($ip)) {
4923
		return false;
4924
	}
4925

    
4926
	$isv6ip = is_ipaddrv6($ip);
4927

    
4928
	/* if list */
4929
	$ifdescrs = get_configured_interface_list();
4930

    
4931
	foreach ($ifdescrs as $ifdescr => $ifname) {
4932
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4933
		if (is_null($ifip)) {
4934
			continue;
4935
		}
4936
		if (is_null($bits)) {
4937
			if ($ip == $ifip) {
4938
				$int = get_real_interface($ifname);
4939
				return $int;
4940
			}
4941
		} else {
4942
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4943
				$int = get_real_interface($ifname);
4944
				return $int;
4945
			}
4946
		}
4947
	}
4948

    
4949
	return false;
4950
}
4951

    
4952
/*
4953
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4954
 *   (or if $bits is specified, where an IP within the subnet is found)
4955
 */
4956
function find_virtual_ip_alias($ip, $bits = null) {
4957
	global $config;
4958

    
4959
	if (!is_array($config['virtualip']['vip'])) {
4960
		return false;
4961
	}
4962
	if (!is_ipaddr($ip)) {
4963
		return false;
4964
	}
4965

    
4966
	$isv6ip = is_ipaddrv6($ip);
4967

    
4968
	foreach ($config['virtualip']['vip'] as $vip) {
4969
		if ($vip['mode'] === "ipalias") {
4970
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4971
				continue;
4972
			}
4973
			if (is_null($bits)) {
4974
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4975
					return $vip;
4976
				}
4977
			} else {
4978
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4979
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4980
					return $vip;
4981
				}
4982
			}
4983
		}
4984
	}
4985
	return false;
4986
}
4987

    
4988
function link_interface_to_track6($int, $action = "") {
4989
	global $config;
4990

    
4991
	if (empty($int)) {
4992
		return;
4993
	}
4994

    
4995
	if (is_array($config['interfaces'])) {
4996
		$list = array();
4997
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4998
			if (!isset($ifcfg['enable'])) {
4999
				continue;
5000
			}
5001
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5002
				if ($action == "update") {
5003
					interface_track6_configure($ifname, $ifcfg);
5004
				} else if ($action == "") {
5005
					$list[$ifname] = $ifcfg;
5006
				}
5007
			}
5008
		}
5009
		return $list;
5010
	}
5011
}
5012

    
5013
function interface_find_child_cfgmtu($realiface) {
5014
	global $config;
5015

    
5016
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5017
	$vlans = link_interface_to_vlans($realiface);
5018
	$qinqs = link_interface_to_qinqs($realiface);
5019
	$bridge = link_interface_to_bridge($realiface);
5020
	if (!empty($interface)) {
5021
		$gifs = link_interface_to_gif($interface);
5022
		$gres = link_interface_to_gre($interface);
5023
	} else {
5024
		$gifs = array();
5025
		$gres = array();
5026
	}
5027

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

    
5089
	return $mtu;
5090
}
5091

    
5092
function link_interface_to_vlans($int, $action = "") {
5093
	global $config;
5094

    
5095
	if (empty($int)) {
5096
		return;
5097
	}
5098

    
5099
	if (is_array($config['vlans']['vlan'])) {
5100
		$ifaces = array();
5101
		foreach ($config['vlans']['vlan'] as $vlan) {
5102
			if ($int == $vlan['if']) {
5103
				if ($action == "update") {
5104
					interfaces_bring_up($int);
5105
				} else {
5106
					$ifaces[$vlan['tag']] = $vlan;
5107
				}
5108
			}
5109
		}
5110
		if (!empty($ifaces)) {
5111
			return $ifaces;
5112
		}
5113
	}
5114
}
5115

    
5116
function link_interface_to_qinqs($int, $action = "") {
5117
	global $config;
5118

    
5119
	if (empty($int)) {
5120
		return;
5121
	}
5122

    
5123
	if (is_array($config['qinqs']['qinqentry'])) {
5124
		$ifaces = array();
5125
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5126
			if ($int == $qinq['if']) {
5127
				if ($action == "update") {
5128
					interfaces_bring_up($int);
5129
				} else {
5130
					$ifaces[$qinq['tag']] = $qinq;
5131
				}
5132
			}
5133
		}
5134
		if (!empty($ifaces)) {
5135
			return $ifaces;
5136
		}
5137
	}
5138
}
5139

    
5140
function link_interface_to_vips($int, $action = "", $vhid = '') {
5141
	global $config;
5142

    
5143
	$updatevips = false;
5144
	if (is_array($config['virtualip']['vip'])) {
5145
		$result = array();
5146
		foreach ($config['virtualip']['vip'] as $vip) {
5147
			if (substr($vip['interface'], 0, 4) == "_vip") {
5148
				$iface = get_configured_vip_interface($vip['interface']);
5149
			} else {
5150
				$iface = $vip['interface'];
5151
			}
5152
			if ($int != $iface) {
5153
				continue;
5154
			}
5155
			if ($action == "update") {
5156
				$updatevips = true;
5157
			} else {
5158
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5159
				    substr($vip['interface'], 0, 4) == "_vip") {
5160
					$result[] = $vip;
5161
				}
5162
			}
5163
		}
5164
		if ($updatevips === true) {
5165
			interfaces_vips_configure($int);
5166
		}
5167
		return $result;
5168
	}
5169

    
5170
	return NULL;
5171
}
5172

    
5173
/****f* interfaces/link_interface_to_bridge
5174
 * NAME
5175
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5176
 * INPUTS
5177
 *   $ip
5178
 * RESULT
5179
 *   bridge[0-99]
5180
 ******/
5181
function link_interface_to_bridge($int) {
5182
	global $config;
5183

    
5184
	if (is_array($config['bridges']['bridged'])) {
5185
		foreach ($config['bridges']['bridged'] as $bridge) {
5186
			if (in_array($int, explode(',', $bridge['members']))) {
5187
				return "{$bridge['bridgeif']}";
5188
			}
5189
		}
5190
	}
5191
}
5192

    
5193
function link_interface_to_group($int) {
5194
	global $config;
5195

    
5196
	$result = array();
5197

    
5198
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5199
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5200
			if (in_array($int, explode(" ", $group['members']))) {
5201
				$result[$group['ifname']] = $int;
5202
			}
5203
		}
5204
	}
5205

    
5206
	return $result;
5207
}
5208

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

    
5212
	$result = array();
5213

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

    
5222
	return $result;
5223
}
5224

    
5225
function link_interface_to_gif($interface) {
5226
	global $config;
5227

    
5228
	$result = array();
5229

    
5230
	if (is_array($config['gifs']['gif'])) {
5231
		foreach ($config['gifs']['gif'] as $gif) {
5232
			if ($gif['if'] == $interface) {
5233
				$result[] = $gif;
5234
			}
5235
		}
5236
	}
5237

    
5238
	return $result;
5239
}
5240

    
5241
/*
5242
 * find_interface_ip($interface): return the interface ip (first found)
5243
 */
5244
function find_interface_ip($interface, $flush = false) {
5245
	global $interface_ip_arr_cache;
5246
	global $interface_sn_arr_cache;
5247

    
5248
	$interface = str_replace("\n", "", $interface);
5249

    
5250
	if (!does_interface_exist($interface)) {
5251
		return;
5252
	}
5253

    
5254
	/* Setup IP cache */
5255
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5256
		if (file_exists("/var/db/${interface}_ip")) {
5257
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5258
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5259
			foreach ($ifaddrs as $ifaddr) {
5260
				list($ip, $mask) = explode("/", $ifaddr);
5261
				if ($ip == $ifip) {
5262
					$interface_ip_arr_cache[$interface] = $ip;
5263
					$interface_sn_arr_cache[$interface] = $mask;
5264
					break;
5265
				}
5266
			}
5267
		}
5268
		if (!isset($interface_ip_arr_cache[$interface])) {
5269
			$ifinfo = pfSense_get_interface_addresses($interface);
5270
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5271
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5272
		}
5273
	}
5274

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

    
5278
/*
5279
 * find_interface_ipv6($interface): return the interface ip (first found)
5280
 */
5281
function find_interface_ipv6($interface, $flush = false) {
5282
	global $interface_ipv6_arr_cache;
5283
	global $interface_snv6_arr_cache;
5284
	global $config;
5285

    
5286
	$interface = trim($interface);
5287
	$interface = get_real_interface($interface);
5288

    
5289
	if (!does_interface_exist($interface)) {
5290
		return;
5291
	}
5292

    
5293
	/* Setup IP cache */
5294
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5295
		$ifinfo = pfSense_get_interface_addresses($interface);
5296
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5297
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5298
	}
5299

    
5300
	return $interface_ipv6_arr_cache[$interface];
5301
}
5302

    
5303
/*
5304
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5305
 */
5306
function find_interface_ipv6_ll($interface, $flush = false) {
5307
	global $interface_llv6_arr_cache;
5308
	global $config;
5309

    
5310
	$interface = str_replace("\n", "", $interface);
5311

    
5312
	if (!does_interface_exist($interface)) {
5313
		return;
5314
	}
5315

    
5316
	/* Setup IP cache */
5317
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5318
		$ifinfo = pfSense_getall_interface_addresses($interface);
5319
		foreach ($ifinfo as $line) {
5320
			if (strstr($line, ":")) {
5321
				$parts = explode("/", $line);
5322
				if (is_linklocal($parts[0])) {
5323
					$ifinfo['linklocal'] = $parts[0];
5324
				}
5325
			}
5326
		}
5327
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5328
	}
5329
	return $interface_llv6_arr_cache[$interface];
5330
}
5331

    
5332
function find_interface_subnet($interface, $flush = false) {
5333
	global $interface_sn_arr_cache;
5334
	global $interface_ip_arr_cache;
5335

    
5336
	$interface = str_replace("\n", "", $interface);
5337
	if (does_interface_exist($interface) == false) {
5338
		return;
5339
	}
5340

    
5341
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5342
		$ifinfo = pfSense_get_interface_addresses($interface);
5343
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5344
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5345
	}
5346

    
5347
	return $interface_sn_arr_cache[$interface];
5348
}
5349

    
5350
function find_interface_subnetv6($interface, $flush = false) {
5351
	global $interface_snv6_arr_cache;
5352
	global $interface_ipv6_arr_cache;
5353

    
5354
	$interface = str_replace("\n", "", $interface);
5355
	if (does_interface_exist($interface) == false) {
5356
		return;
5357
	}
5358

    
5359
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5360
		$ifinfo = pfSense_get_interface_addresses($interface);
5361
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5362
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5363
	}
5364

    
5365
	return $interface_snv6_arr_cache[$interface];
5366
}
5367

    
5368
function ip_in_interface_alias_subnet($interface, $ipalias) {
5369
	global $config;
5370

    
5371
	if (empty($interface) || !is_ipaddr($ipalias)) {
5372
		return false;
5373
	}
5374
	if (is_array($config['virtualip']['vip'])) {
5375
		foreach ($config['virtualip']['vip'] as $vip) {
5376
			switch ($vip['mode']) {
5377
				case "ipalias":
5378
					if ($vip['interface'] <> $interface) {
5379
						break;
5380
					}
5381
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5382
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5383
						return true;
5384
					}
5385
					break;
5386
			}
5387
		}
5388
	}
5389

    
5390
	return false;
5391
}
5392

    
5393
function get_possible_listen_ips($include_ipv6_link_local=false) {
5394

    
5395
	$interfaces = get_configured_interface_with_descr();
5396
	foreach ($interfaces as $iface => $ifacename) {
5397
		if ($include_ipv6_link_local) {
5398
			/* This is to avoid going though added ll below */
5399
			if (substr($iface, 0, 5) == '_lloc') {
5400
				continue;
5401
			}
5402
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5403
			if (!empty($llip)) {
5404
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5405
			}
5406
		}
5407
	}
5408
	$viplist = get_configured_vip_list();
5409
	foreach ($viplist as $vip => $address) {
5410
		$interfaces[$vip] = $address;
5411
		if (get_vip_descr($address)) {
5412
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5413
		}
5414
	}
5415

    
5416
	$interfaces['lo0'] = 'Localhost';
5417

    
5418
	return $interfaces;
5419
}
5420

    
5421
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5422
	global $config;
5423

    
5424
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5425
	foreach (array('server', 'client') as $mode) {
5426
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5427
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5428
				if (!isset($setting['disable'])) {
5429
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5430
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5431
				}
5432
			}
5433
		}
5434
	}
5435
	return $sourceips;
5436
}
5437

    
5438
function get_interface_ip($interface = "wan") {
5439

    
5440
	if (substr($interface, 0, 4) == '_vip') {
5441
		return get_configured_vip_ipv4($interface);
5442
	} else if (substr($interface, 0, 5) == '_lloc') {
5443
		/* No link-local address for v4. */
5444
		return null;
5445
	}
5446

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

    
5452
	if (substr($realif, 0, 4) == '_vip') {
5453
		return get_configured_vip_ipv4($realif);
5454
	} else if (substr($realif, 0, 5) == '_lloc') {
5455
		/* No link-local address for v4. */
5456
		return null;
5457
	}
5458

    
5459
	if (is_array($config['interfaces'][$interface]) &&
5460
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5461
		return ($config['interfaces'][$interface]['ipaddr']);
5462
	}
5463

    
5464
	/*
5465
	 * Beaware that find_interface_ip() is our last option, it will
5466
	 * return the first IP it find on interface, not necessarily the
5467
	 * main IP address.
5468
	 */
5469
	$curip = find_interface_ip($realif);
5470
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5471
		return $curip;
5472
	} else {
5473
		return null;
5474
	}
5475
}
5476

    
5477
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5478
	global $config;
5479

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

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

    
5491
	if (substr($realif, 0, 4) == '_vip') {
5492
		return get_configured_vip_ipv6($realif);
5493
	} else if (substr($realif, 0, 5) == '_lloc') {
5494
		return get_interface_linklocal($realif);
5495
	}
5496

    
5497
	if (is_array($config['interfaces'][$interface])) {
5498
		switch ($config['interfaces'][$interface]['ipaddr']) {
5499
			case 'pppoe':
5500
			case 'l2tp':
5501
			case 'pptp':
5502
			case 'ppp':
5503
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5504
					$realif = get_real_interface($interface, 'inet6', false);
5505
				}
5506
				break;
5507
		}
5508
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5509
			return ($config['interfaces'][$interface]['ipaddrv6']);
5510
		}
5511
	}
5512

    
5513
	/*
5514
	 * Beaware that find_interface_ip() is our last option, it will
5515
	 * return the first IP it find on interface, not necessarily the
5516
	 * main IP address.
5517
	 */
5518
	$curip = find_interface_ipv6($realif, $flush);
5519
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5520
		return $curip;
5521
	} else {
5522
		/*
5523
		 * NOTE: On the case when only the prefix is requested,
5524
		 * the communication on WAN will be done over link-local.
5525
		 */
5526
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5527
			$curip = find_interface_ipv6_ll($realif, $flush);
5528
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5529
				return $curip;
5530
			}
5531
		}
5532
	}
5533
	return null;
5534
}
5535

    
5536
function get_interface_linklocal($interface = "wan") {
5537

    
5538
	$realif = get_failover_interface($interface, 'inet6');
5539
	if (!$realif) {
5540
		return null;
5541
	}
5542

    
5543
	if (substr($interface, 0, 4) == '_vip') {
5544
		$realif = get_real_interface($interface);
5545
	} else if (substr($interface, 0, 5) == '_lloc') {
5546
		$realif = get_real_interface(substr($interface, 5));
5547
	}
5548

    
5549
	$curip = find_interface_ipv6_ll($realif);
5550
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5551
		return $curip;
5552
	} else {
5553
		return null;
5554
	}
5555
}
5556

    
5557
function get_interface_subnet($interface = "wan") {
5558

    
5559
	if (substr($interface, 0, 4) == '_vip') {
5560
		return (get_configured_vip_subnetv4($interface));
5561
	}
5562

    
5563
	$realif = get_real_interface($interface);
5564
	if (!$realif) {
5565
		return (NULL);
5566
	}
5567

    
5568
	$cursn = find_interface_subnet($realif);
5569
	if (!empty($cursn)) {
5570
		return ($cursn);
5571
	}
5572

    
5573
	return (NULL);
5574
}
5575

    
5576
function get_interface_subnetv6($interface = "wan") {
5577

    
5578
	if (substr($interface, 0, 4) == '_vip') {
5579
		return (get_configured_vip_subnetv6($interface));
5580
	} else if (substr($interface, 0, 5) == '_lloc') {
5581
		$interface = substr($interface, 5);
5582
	}
5583

    
5584
	$realif = get_real_interface($interface, 'inet6');
5585
	if (!$realif) {
5586
		return (NULL);
5587
	}
5588

    
5589
	$cursn = find_interface_subnetv6($realif);
5590
	if (!empty($cursn)) {
5591
		return ($cursn);
5592
	}
5593

    
5594
	return (NULL);
5595
}
5596

    
5597
/* return outside interfaces with a gateway */
5598
function get_interfaces_with_gateway() {
5599
	global $config;
5600

    
5601
	$ints = array();
5602

    
5603
	/* loop interfaces, check config for outbound */
5604
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5605
		switch ($ifname['ipaddr']) {
5606
			case "dhcp":
5607
			case "pppoe":
5608
			case "pptp":
5609
			case "l2tp":
5610
			case "ppp":
5611
				$ints[$ifdescr] = $ifdescr;
5612
				break;
5613
			default:
5614
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5615
				    !empty($ifname['gateway'])) {
5616
					$ints[$ifdescr] = $ifdescr;
5617
				}
5618
				break;
5619
		}
5620
	}
5621
	return $ints;
5622
}
5623

    
5624
/* return true if interface has a gateway */
5625
function interface_has_gateway($friendly) {
5626
	global $config;
5627

    
5628
	if (!empty($config['interfaces'][$friendly])) {
5629
		$ifname = &$config['interfaces'][$friendly];
5630
		switch ($ifname['ipaddr']) {
5631
			case "dhcp":
5632
			case "pppoe":
5633
			case "pptp":
5634
			case "l2tp":
5635
			case "ppp":
5636
				return true;
5637
			break;
5638
			default:
5639
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5640
					return true;
5641
				}
5642
				$tunnelif = substr($ifname['if'], 0, 3);
5643
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5644
					if (find_interface_ip($ifname['if'])) {
5645
						return true;
5646
					}
5647
				}
5648
				if (!empty($ifname['gateway'])) {
5649
					return true;
5650
				}
5651
			break;
5652
		}
5653
	}
5654

    
5655
	return false;
5656
}
5657

    
5658
/* return true if interface has a gateway */
5659
function interface_has_gatewayv6($friendly) {
5660
	global $config;
5661

    
5662
	if (!empty($config['interfaces'][$friendly])) {
5663
		$ifname = &$config['interfaces'][$friendly];
5664
		switch ($ifname['ipaddrv6']) {
5665
			case "slaac":
5666
			case "dhcp6":
5667
			case "6to4":
5668
			case "6rd":
5669
				return true;
5670
				break;
5671
			default:
5672
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5673
					return true;
5674
				}
5675
				$tunnelif = substr($ifname['if'], 0, 3);
5676
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5677
					if (find_interface_ipv6($ifname['if'])) {
5678
						return true;
5679
					}
5680
				}
5681
				if (!empty($ifname['gatewayv6'])) {
5682
					return true;
5683
				}
5684
				break;
5685
		}
5686
	}
5687

    
5688
	return false;
5689
}
5690

    
5691
/****f* interfaces/is_altq_capable
5692
 * NAME
5693
 *   is_altq_capable - Test if interface is capable of using ALTQ
5694
 * INPUTS
5695
 *   $int            - string containing interface name
5696
 * RESULT
5697
 *   boolean         - true or false
5698
 ******/
5699

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

    
5714
	$int_family = remove_ifindex($int);
5715

    
5716
	if (in_array($int_family, $capable)) {
5717
		return true;
5718
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5719
		return true;
5720
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5721
		return true;
5722
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5723
		return true;
5724
	} else {
5725
		return false;
5726
	}
5727
}
5728

    
5729
/****f* interfaces/is_interface_wireless
5730
 * NAME
5731
 *   is_interface_wireless - Returns if an interface is wireless
5732
 * RESULT
5733
 *   $tmp       - Returns if an interface is wireless
5734
 ******/
5735
function is_interface_wireless($interface) {
5736
	global $config, $g;
5737

    
5738
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5739
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5740
		if (preg_match($g['wireless_regex'], $interface)) {
5741
			if (isset($config['interfaces'][$friendly])) {
5742
				$config['interfaces'][$friendly]['wireless'] = array();
5743
			}
5744
			return true;
5745
		}
5746
		return false;
5747
	} else {
5748
		return true;
5749
	}
5750
}
5751

    
5752
function get_wireless_modes($interface) {
5753
	/* return wireless modes and channels */
5754
	$wireless_modes = array();
5755

    
5756
	$cloned_interface = get_real_interface($interface);
5757

    
5758
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5759
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5760
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5761
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5762

    
5763
		$interface_channels = "";
5764
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5765
		$interface_channel_count = count($interface_channels);
5766

    
5767
		$c = 0;
5768
		while ($c < $interface_channel_count) {
5769
			$channel_line = explode(",", $interface_channels["$c"]);
5770
			$wireless_mode = trim($channel_line[0]);
5771
			$wireless_channel = trim($channel_line[1]);
5772
			if (trim($wireless_mode) != "") {
5773
				/* if we only have 11g also set 11b channels */
5774
				if ($wireless_mode == "11g") {
5775
					if (!isset($wireless_modes["11b"])) {
5776
						$wireless_modes["11b"] = array();
5777
					}
5778
				} else if ($wireless_mode == "11g ht") {
5779
					if (!isset($wireless_modes["11b"])) {
5780
						$wireless_modes["11b"] = array();
5781
					}
5782
					if (!isset($wireless_modes["11g"])) {
5783
						$wireless_modes["11g"] = array();
5784
					}
5785
					$wireless_mode = "11ng";
5786
				} else if ($wireless_mode == "11a ht") {
5787
					if (!isset($wireless_modes["11a"])) {
5788
						$wireless_modes["11a"] = array();
5789
					}
5790
					$wireless_mode = "11na";
5791
				}
5792
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5793
			}
5794
			$c++;
5795
		}
5796
	}
5797
	return($wireless_modes);
5798
}
5799

    
5800
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5801
function get_wireless_channel_info($interface) {
5802
	$wireless_channels = array();
5803

    
5804
	$cloned_interface = get_real_interface($interface);
5805

    
5806
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5807
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5808
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5809
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5810

    
5811
		$interface_channels = "";
5812
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5813

    
5814
		foreach ($interface_channels as $channel_line) {
5815
			$channel_line = explode(",", $channel_line);
5816
			if (!isset($wireless_channels[$channel_line[0]])) {
5817
				$wireless_channels[$channel_line[0]] = $channel_line;
5818
			}
5819
		}
5820
	}
5821
	return($wireless_channels);
5822
}
5823

    
5824
function set_interface_mtu($interface, $mtu) {
5825

    
5826
	/* LAGG interface must be destroyed and re-created to change MTU */
5827
	if (substr($interface, 0, 4) == 'lagg') {
5828
		if (isset($config['laggs']['lagg']) &&
5829
		    is_array($config['laggs']['lagg'])) {
5830
			foreach ($config['laggs']['lagg'] as $lagg) {
5831
				if ($lagg['laggif'] == $interface) {
5832
					interface_lagg_configure($lagg);
5833
					break;
5834
				}
5835
			}
5836
		}
5837
	} else {
5838
		pfSense_interface_mtu($interface, $mtu);
5839
	}
5840
}
5841

    
5842
/****f* interfaces/get_interface_mtu
5843
 * NAME
5844
 *   get_interface_mtu - Return the mtu of an interface
5845
 * RESULT
5846
 *   $tmp       - Returns the mtu of an interface
5847
 ******/
5848
function get_interface_mtu($interface) {
5849
	$mtu = pfSense_interface_getmtu($interface);
5850
	return $mtu['mtu'];
5851
}
5852

    
5853
function get_interface_mac($interface) {
5854

    
5855
	$macinfo = pfSense_get_interface_addresses($interface);
5856
	return $macinfo["macaddr"];
5857
}
5858

    
5859
/****f* pfsense-utils/generate_random_mac_address
5860
 * NAME
5861
 *   generate_random_mac - generates a random mac address
5862
 * INPUTS
5863
 *   none
5864
 * RESULT
5865
 *   $mac - a random mac address
5866
 ******/
5867
function generate_random_mac_address() {
5868
	$mac = "02";
5869
	for ($x = 0; $x < 5; $x++) {
5870
		$mac .= ":" . dechex(rand(16, 255));
5871
	}
5872
	return $mac;
5873
}
5874

    
5875
/****f* interfaces/is_jumbo_capable
5876
 * NAME
5877
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5878
 * INPUTS
5879
 *   $int             - string containing interface name
5880
 * RESULT
5881
 *   boolean          - true or false
5882
 ******/
5883
function is_jumbo_capable($iface) {
5884
	$iface = trim($iface);
5885
	$capable = pfSense_get_interface_addresses($iface);
5886

    
5887
	if (isset($capable['caps']['vlanmtu'])) {
5888
		return true;
5889
	}
5890

    
5891
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5892
	if (substr($iface, 0, 4) == "lagg") {
5893
		return true;
5894
	}
5895

    
5896
	return false;
5897
}
5898

    
5899
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5900
	global $g;
5901

    
5902
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5903

    
5904
	if (!empty($iface) && !empty($pppif)) {
5905
		$cron_cmd = <<<EOD
5906
#!/bin/sh
5907
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5908
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5909

    
5910
EOD;
5911

    
5912
		@file_put_contents($cron_file, $cron_cmd);
5913
		chmod($cron_file, 0755);
5914
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5915
	} else {
5916
		unlink_if_exists($cron_file);
5917
	}
5918
}
5919

    
5920
function get_interface_default_mtu($type = "ethernet") {
5921
	switch ($type) {
5922
		case "gre":
5923
			return 1476;
5924
			break;
5925
		case "gif":
5926
			return 1280;
5927
			break;
5928
		case "tun":
5929
		case "vlan":
5930
		case "tap":
5931
		case "ethernet":
5932
		default:
5933
			return 1500;
5934
			break;
5935
	}
5936

    
5937
	/* Never reached */
5938
	return 1500;
5939
}
5940

    
5941
function get_vip_descr($ipaddress) {
5942
	global $config;
5943

    
5944
	foreach ($config['virtualip']['vip'] as $vip) {
5945
		if ($vip['subnet'] == $ipaddress) {
5946
			return ($vip['descr']);
5947
		}
5948
	}
5949
	return "";
5950
}
5951

    
5952
function interfaces_staticarp_configure($if) {
5953
	global $config, $g;
5954
	if (isset($config['system']['developerspew'])) {
5955
		$mt = microtime();
5956
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5957
	}
5958

    
5959
	$ifcfg = $config['interfaces'][$if];
5960

    
5961
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5962
		return 0;
5963
	}
5964

    
5965
	/* Enable staticarp, if enabled */
5966
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5967
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5968
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5969
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5970
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5971
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
5972
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5973
				}
5974
			}
5975
		}
5976
	} else {
5977
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5978
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5979
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5980
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5981
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
5982
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5983
				}
5984
			}
5985
		}
5986
	}
5987

    
5988
	return 0;
5989
}
5990

    
5991
function get_failover_interface($interface, $family = "all") {
5992
	global $config;
5993

    
5994
	/* shortcut to get_real_interface if we find it in the config */
5995
	if (is_array($config['interfaces'][$interface])) {
5996
		return get_real_interface($interface, $family);
5997
	}
5998

    
5999
	/* compare against gateway groups */
6000
	$a_groups = return_gateway_groups_array();
6001
	if (is_array($a_groups[$interface])) {
6002
		/* we found a gateway group, fetch the interface or vip */
6003
		if (!empty($a_groups[$interface][0]['vip'])) {
6004
			return $a_groups[$interface][0]['vip'];
6005
		} else {
6006
			return $a_groups[$interface][0]['int'];
6007
		}
6008
	}
6009
	/* fall through to get_real_interface */
6010
	/* XXX: Really needed? */
6011
	return get_real_interface($interface, $family);
6012
}
6013

    
6014
/****f* interfaces/interface_has_dhcp
6015
 * NAME
6016
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6017
 * INPUTS
6018
 *   interface or gateway group name
6019
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6020
 * RESULT
6021
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6022
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6023
 ******/
6024
function interface_has_dhcp($interface, $family = 4) {
6025
	global $config;
6026

    
6027
	if ($config['interfaces'][$interface]) {
6028
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6029
			return true;
6030
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6031
			return true;
6032
		} else {
6033
			return false;
6034
		}
6035
	}
6036

    
6037
	if (!is_array($config['gateways']['gateway_group'])) {
6038
		return false;
6039
	}
6040

    
6041
	if ($family == 6) {
6042
		$dhcp_string = "_DHCP6";
6043
	} else {
6044
		$dhcp_string = "_DHCP";
6045
	}
6046

    
6047
	foreach ($config['gateways']['gateway_group'] as $group) {
6048
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6049
			continue;
6050
		}
6051
		foreach ($group['item'] as $item) {
6052
			$item_data = explode("|", $item);
6053
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6054
				return true;
6055
			}
6056
		}
6057
	}
6058

    
6059
	return false;
6060
}
6061

    
6062
function remove_ifindex($ifname) {
6063
	return preg_replace("/[0-9]+$/", "", $ifname);
6064
}
6065

    
6066
?>
(18-18/51)