Project

General

Profile

Download (172 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_isppp_type($interface) {
1418
	global $config;
1419

    
1420
	if (!is_array($config['interfaces'][$interface])) {
1421
		return false;
1422
	}
1423

    
1424
	switch ($config['interfaces'][$interface]['ipaddr']) {
1425
		case 'pptp':
1426
		case 'l2tp':
1427
		case 'pppoe':
1428
		case 'ppp':
1429
			return true;
1430
			break;
1431
		default:
1432
			return false;
1433
			break;
1434
	}
1435
}
1436

    
1437
function interfaces_ptpid_used($ptpid) {
1438
	global $config;
1439

    
1440
	if (is_array($config['ppps']['ppp'])) {
1441
		foreach ($config['ppps']['ppp'] as & $settings) {
1442
			if ($ptpid == $settings['ptpid']) {
1443
				return true;
1444
			}
1445
		}
1446
	}
1447

    
1448
	return false;
1449
}
1450

    
1451
function interfaces_ptpid_next() {
1452

    
1453
	$ptpid = 0;
1454
	while (interfaces_ptpid_used($ptpid)) {
1455
		$ptpid++;
1456
	}
1457

    
1458
	return $ptpid;
1459
}
1460

    
1461
function getMPDCRONSettings($pppif) {
1462
	global $config;
1463

    
1464
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1465
	if (is_array($config['cron']['item'])) {
1466
		foreach ($config['cron']['item'] as $i => $item) {
1467
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1468
				return array("ID" => $i, "ITEM" => $item);
1469
			}
1470
		}
1471
	}
1472

    
1473
	return NULL;
1474
}
1475

    
1476
function handle_pppoe_reset($post_array) {
1477
	global $config, $g;
1478

    
1479
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1480
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1481

    
1482
	if (!is_array($config['cron']['item'])) {
1483
		$config['cron']['item'] = array();
1484
	}
1485

    
1486
	$itemhash = getMPDCRONSettings($pppif);
1487

    
1488
	// reset cron items if necessary and return
1489
	if (empty($post_array['pppoe-reset-type'])) {
1490
		if (isset($itemhash)) {
1491
			unset($config['cron']['item'][$itemhash['ID']]);
1492
		}
1493
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1494
		return;
1495
	}
1496

    
1497
	if (empty($itemhash)) {
1498
		$itemhash = array();
1499
	}
1500
	$item = array();
1501
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1502
		$item['minute'] = $post_array['pppoe_resetminute'];
1503
		$item['hour'] = $post_array['pppoe_resethour'];
1504
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1505
			$date = explode("/", $post_array['pppoe_resetdate']);
1506
			$item['mday'] = $date[1];
1507
			$item['month'] = $date[0];
1508
		} else {
1509
			$item['mday'] = "*";
1510
			$item['month'] = "*";
1511
		}
1512
		$item['wday'] = "*";
1513
		$item['who'] = "root";
1514
		$item['command'] = $cron_cmd_file;
1515
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1516
		switch ($post_array['pppoe_pr_preset_val']) {
1517
			case "monthly":
1518
				$item['minute'] = "0";
1519
				$item['hour'] = "0";
1520
				$item['mday'] = "1";
1521
				$item['month'] = "*";
1522
				$item['wday'] = "*";
1523
				break;
1524
			case "weekly":
1525
				$item['minute'] = "0";
1526
				$item['hour'] = "0";
1527
				$item['mday'] = "*";
1528
				$item['month'] = "*";
1529
				$item['wday'] = "0";
1530
				break;
1531
			case "daily":
1532
				$item['minute'] = "0";
1533
				$item['hour'] = "0";
1534
				$item['mday'] = "*";
1535
				$item['month'] = "*";
1536
				$item['wday'] = "*";
1537
				break;
1538
			case "hourly":
1539
				$item['minute'] = "0";
1540
				$item['hour'] = "*";
1541
				$item['mday'] = "*";
1542
				$item['month'] = "*";
1543
				$item['wday'] = "*";
1544
				break;
1545
		} // end switch
1546
		$item['who'] = "root";
1547
		$item['command'] = $cron_cmd_file;
1548
	}
1549
	if (empty($item)) {
1550
		return;
1551
	}
1552
	if (isset($itemhash['ID'])) {
1553
		$config['cron']['item'][$itemhash['ID']] = $item;
1554
	} else {
1555
		$config['cron']['item'][] = $item;
1556
	}
1557
}
1558

    
1559
/*
1560
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1561
 * It writes the mpd config file to /var/etc every time the link is opened.
1562
 */
1563
function interface_ppps_configure($interface) {
1564
	global $config, $g;
1565

    
1566
	/* Return for unassigned interfaces. This is a minimum requirement. */
1567
	if (empty($config['interfaces'][$interface])) {
1568
		return 0;
1569
	}
1570
	$ifcfg = $config['interfaces'][$interface];
1571
	if (!isset($ifcfg['enable'])) {
1572
		return 0;
1573
	}
1574

    
1575
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1576
	if (!is_dir("/var/spool/lock")) {
1577
		mkdir("/var/spool/lock", 0777, true);
1578
	}
1579
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1580
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1581
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1582
	}
1583

    
1584
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1585
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1586
			if ($ifcfg['if'] == $ppp['if']) {
1587
				break;
1588
			}
1589
		}
1590
	}
1591
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1592
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1593
		return 0;
1594
	}
1595
	$pppif = $ifcfg['if'];
1596
	if ($ppp['type'] == "ppp") {
1597
		$type = "modem";
1598
	} else {
1599
		$type = $ppp['type'];
1600
	}
1601
	$upper_type = strtoupper($ppp['type']);
1602

    
1603
	/* XXX: This does not make sense and may create trouble
1604
	 * comment it for now to be removed later on.
1605
	if (platform_booting()) {
1606
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1607
		echo "starting {$pppif} link...";
1608
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1609
			return 0;
1610
	}
1611
	*/
1612

    
1613
	$ports = explode(',', $ppp['ports']);
1614
	if ($type != "modem") {
1615
		foreach ($ports as $pid => $port) {
1616
			$ports[$pid] = get_real_interface($port);
1617
			if (empty($ports[$pid])) {
1618
				return 0;
1619
			}
1620
		}
1621
	}
1622
	$localips = explode(',', $ppp['localip']);
1623
	$gateways = explode(',', $ppp['gateway']);
1624
	$subnets = explode(',', $ppp['subnet']);
1625

    
1626
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1627
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1628
	 */
1629
	foreach ($ports as $pid => $port) {
1630
		switch ($ppp['type']) {
1631
			case "pppoe":
1632
				/* Bring the parent interface up */
1633
				interfaces_bring_up($port);
1634
				pfSense_ngctl_attach(".", $port);
1635
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1636
				mwexec("/usr/sbin/ngctl msg {$port}: setautosrc 1");
1637
				break;
1638
			case "pptp":
1639
			case "l2tp":
1640
				/* configure interface */
1641
				if (is_ipaddr($localips[$pid])) {
1642
					// Manually configure interface IP/subnet
1643
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1644
					interfaces_bring_up($port);
1645
				} else if (empty($localips[$pid])) {
1646
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1647
				}
1648

    
1649
				if (!is_ipaddr($localips[$pid])) {
1650
					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));
1651
					$localips[$pid] = "0.0.0.0";
1652
				}
1653
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1654
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1655
				}
1656
				if (!is_ipaddr($gateways[$pid])) {
1657
					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));
1658
					return 0;
1659
				}
1660
				pfSense_ngctl_attach(".", $port);
1661
				break;
1662
			case "ppp":
1663
				if (!file_exists("{$port}")) {
1664
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1665
					return 0;
1666
				}
1667
				break;
1668
			default:
1669
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1670
				break;
1671
		}
1672
	}
1673

    
1674
	if (is_array($ports) && count($ports) > 1) {
1675
		$multilink = "enable";
1676
	} else {
1677
		$multilink = "disable";
1678
	}
1679

    
1680
	if ($type == "modem") {
1681
		if (is_ipaddr($ppp['localip'])) {
1682
			$localip = $ppp['localip'];
1683
		} else {
1684
			$localip = '0.0.0.0';
1685
		}
1686

    
1687
		if (is_ipaddr($ppp['gateway'])) {
1688
			$gateway = $ppp['gateway'];
1689
		} else {
1690
			$gateway = "10.64.64.{$pppid}";
1691
		}
1692
		$ranges = "{$localip}/0 {$gateway}/0";
1693

    
1694
		if (empty($ppp['apnum'])) {
1695
			$ppp['apnum'] = 1;
1696
		}
1697
	} else {
1698
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1699
	}
1700

    
1701
	if (isset($ppp['ondemand'])) {
1702
		$ondemand = "enable";
1703
	} else {
1704
		$ondemand = "disable";
1705
	}
1706
	if (!isset($ppp['idletimeout'])) {
1707
		$ppp['idletimeout'] = 0;
1708
	}
1709

    
1710
	if (empty($ppp['username']) && $type == "modem") {
1711
		$ppp['username'] = "user";
1712
		$ppp['password'] = "none";
1713
	}
1714
	if (empty($ppp['password']) && $type == "modem") {
1715
		$passwd = "none";
1716
	} else {
1717
		$passwd = base64_decode($ppp['password']);
1718
	}
1719

    
1720
	$bandwidths = explode(',', $ppp['bandwidth']);
1721
	$defaultmtu = "1492";
1722
	if (!empty($ifcfg['mtu'])) {
1723
		$defaultmtu = intval($ifcfg['mtu']);
1724
	}
1725
	if (isset($ppp['mtu'])) {
1726
		$mtus = explode(',', $ppp['mtu']);
1727
	}
1728
	if (isset($ppp['mru'])) {
1729
		$mrus = explode(',', $ppp['mru']);
1730
	}
1731
	if (isset($ppp['mrru'])) {
1732
		$mrrus = explode(',', $ppp['mrru']);
1733
	}
1734

    
1735
	// Construct the mpd.conf file
1736
	$mpdconf = <<<EOD
1737
startup:
1738
	# configure the console
1739
	set console close
1740
	# configure the web server
1741
	set web close
1742

    
1743
default:
1744
{$ppp['type']}client:
1745
	create bundle static {$interface}
1746
	set bundle enable ipv6cp
1747
	set iface name {$pppif}
1748

    
1749
EOD;
1750
	$setdefaultgw = false;
1751
	$founddefaultgw = false;
1752
	if (is_array($config['gateways']['gateway_item'])) {
1753
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1754
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1755
				$setdefaultgw = true;
1756
				break;
1757
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1758
				$founddefaultgw = true;
1759
				break;
1760
			}
1761
		}
1762
	}
1763

    
1764
/* Omit this, we maintain the default route by other means, and it causes problems with
1765
 * default gateway switching. See redmine #1837 for original issue
1766
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
1767
 * edge case. redmine #6495 open to address.
1768
 */
1769
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1770
		$setdefaultgw = true;
1771
		$mpdconf .= <<<EOD
1772
	set iface route default
1773

    
1774
EOD;
1775
	}
1776
	$mpdconf .= <<<EOD
1777
	set iface {$ondemand} on-demand
1778
	set iface idle {$ppp['idletimeout']}
1779

    
1780
EOD;
1781

    
1782
	if (isset($ppp['ondemand'])) {
1783
		$mpdconf .= <<<EOD
1784
	set iface addrs 10.10.1.1 10.10.1.2
1785

    
1786
EOD;
1787
	}
1788

    
1789
	if (isset($ppp['tcpmssfix'])) {
1790
		$tcpmss = "disable";
1791
	} else {
1792
		$tcpmss = "enable";
1793
	}
1794
	$mpdconf .= <<<EOD
1795
	set iface {$tcpmss} tcpmssfix
1796

    
1797
EOD;
1798

    
1799
	$mpdconf .= <<<EOD
1800
	set iface up-script /usr/local/sbin/ppp-linkup
1801
	set iface down-script /usr/local/sbin/ppp-linkdown
1802
	set ipcp ranges {$ranges}
1803

    
1804
EOD;
1805
	if (isset($ppp['vjcomp'])) {
1806
		$mpdconf .= <<<EOD
1807
	set ipcp no vjcomp
1808

    
1809
EOD;
1810
	}
1811

    
1812
	if (isset($config['system']['dnsallowoverride'])) {
1813
		$mpdconf .= <<<EOD
1814
	set ipcp enable req-pri-dns
1815
	set ipcp enable req-sec-dns
1816

    
1817
EOD;
1818
	}
1819

    
1820
	if (!isset($ppp['verbose_log'])) {
1821
		$mpdconf .= <<<EOD
1822
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1823

    
1824
EOD;
1825
	}
1826

    
1827
	foreach ($ports as $pid => $port) {
1828
		$port = get_real_interface($port);
1829
		$mpdconf .= <<<EOD
1830

    
1831
	create link static {$interface}_link{$pid} {$type}
1832
	set link action bundle {$interface}
1833
	set link {$multilink} multilink
1834
	set link keep-alive 10 60
1835
	set link max-redial 0
1836

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

    
1842
EOD;
1843
		}
1844

    
1845
		if (isset($ppp['acfcomp'])) {
1846
			$mpdconf .= <<<EOD
1847
	set link no acfcomp
1848

    
1849
EOD;
1850
		}
1851

    
1852
		if (isset($ppp['protocomp'])) {
1853
			$mpdconf .= <<<EOD
1854
	set link no protocomp
1855

    
1856
EOD;
1857
		}
1858

    
1859
		$mpdconf .= <<<EOD
1860
	set link disable chap pap
1861
	set link accept chap pap eap
1862
	set link disable incoming
1863

    
1864
EOD;
1865

    
1866

    
1867
		if (!empty($bandwidths[$pid])) {
1868
			$mpdconf .= <<<EOD
1869
	set link bandwidth {$bandwidths[$pid]}
1870

    
1871
EOD;
1872
		}
1873

    
1874
		if (empty($mtus[$pid])) {
1875
			$mtus[$pid] = $defaultmtu;
1876
		}
1877
		if ($type == "pppoe") {
1878
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
1879
				$mtus[$pid] = get_interface_mtu($port) - 8;
1880
			}
1881
		}
1882
		if (! ($type == "pppoe" && $mtus[$pid] > 1492) ) {
1883
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
1884
			$mpdconf .= <<<EOD
1885
	set link mtu {$mtus[$pid]}
1886

    
1887
EOD;
1888
		}
1889

    
1890
		if (!empty($mrus[$pid])) {
1891
			$mpdconf .= <<<EOD
1892
	set link mru {$mrus[$pid]}
1893

    
1894
EOD;
1895
		}
1896

    
1897
		if (!empty($mrrus[$pid])) {
1898
			$mpdconf .= <<<EOD
1899
	set link mrru {$mrrus[$pid]}
1900

    
1901
EOD;
1902
		}
1903

    
1904
		$mpdconf .= <<<EOD
1905
	set auth authname "{$ppp['username']}"
1906
	set auth password {$passwd}
1907

    
1908
EOD;
1909
		if ($type == "modem") {
1910
			$mpdconf .= <<<EOD
1911
	set modem device {$ppp['ports']}
1912
	set modem script DialPeer
1913
	set modem idle-script Ringback
1914
	set modem watch -cd
1915
	set modem var \$DialPrefix "DT"
1916
	set modem var \$Telephone "{$ppp['phone']}"
1917

    
1918
EOD;
1919
		}
1920
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1921
			$mpdconf .= <<<EOD
1922
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1923

    
1924
EOD;
1925
		}
1926
		if (isset($ppp['initstr']) && $type == "modem") {
1927
			$initstr = base64_decode($ppp['initstr']);
1928
			$mpdconf .= <<<EOD
1929
	set modem var \$InitString "{$initstr}"
1930

    
1931
EOD;
1932
		}
1933
		if (isset($ppp['simpin']) && $type == "modem") {
1934
			if ($ppp['pin-wait'] == "") {
1935
				$ppp['pin-wait'] = 0;
1936
			}
1937
			$mpdconf .= <<<EOD
1938
	set modem var \$SimPin "{$ppp['simpin']}"
1939
	set modem var \$PinWait "{$ppp['pin-wait']}"
1940

    
1941
EOD;
1942
		}
1943
		if (isset($ppp['apn']) && $type == "modem") {
1944
			$mpdconf .= <<<EOD
1945
	set modem var \$APN "{$ppp['apn']}"
1946
	set modem var \$APNum "{$ppp['apnum']}"
1947

    
1948
EOD;
1949
		}
1950
		if ($type == "pppoe") {
1951
			// Send a null service name if none is set.
1952
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1953
			$mpdconf .= <<<EOD
1954
	set pppoe service "{$provider}"
1955

    
1956
EOD;
1957
		}
1958
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
1959
			$mpdconf .= <<<EOD
1960
	set pppoe max-payload {$mtus[$pid]}
1961

    
1962
EOD;
1963
		}
1964
		if ($type == "pppoe") {
1965
			$mpdconf .= <<<EOD
1966
	set pppoe iface {$port}
1967

    
1968
EOD;
1969
		}
1970

    
1971
		if ($type == "pptp" || $type == "l2tp") {
1972
			$mpdconf .= <<<EOD
1973
	set {$type} self {$localips[$pid]}
1974
	set {$type} peer {$gateways[$pid]}
1975

    
1976
EOD;
1977
		}
1978

    
1979
		$mpdconf .= "\topen\n";
1980
	} //end foreach ($port)
1981

    
1982

    
1983
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1984
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
1985
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1986
	} else {
1987
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1988
		if (!$fd) {
1989
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
1990
			return 0;
1991
		}
1992
		// Write out mpd_ppp.conf
1993
		fwrite($fd, $mpdconf);
1994
		fclose($fd);
1995
		unset($mpdconf);
1996
	}
1997

    
1998
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1999
	if (isset($ppp['uptime'])) {
2000
		if (!file_exists("/conf/{$pppif}.log")) {
2001
			file_put_contents("/conf/{$pppif}.log", '');
2002
		}
2003
	} else {
2004
		if (file_exists("/conf/{$pppif}.log")) {
2005
			@unlink("/conf/{$pppif}.log");
2006
		}
2007
	}
2008

    
2009
	/* clean up old lock files */
2010
	foreach ($ports as $port) {
2011
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2012
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2013
		}
2014
	}
2015

    
2016
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2017
	/* random IPv6 interface identifier during boot. More details at */
2018
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2019
	if (platform_booting() && is_array($config['interfaces'])) {
2020
		$count = 0;
2021
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2022
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2023
				$tempaddr[$count]['if'] = $tempiface['if'];
2024
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2025
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2026
				$count++;
2027
			}
2028
			// Maximum /31 is is x.y.z.254/31
2029
			if ($count > 122) {
2030
				break;
2031
			}
2032
		}
2033
		unset($count);
2034
	}
2035

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

    
2041
	// Check for PPPoE periodic reset request
2042
	if ($type == "pppoe") {
2043
		if (!empty($ppp['pppoe-reset-type'])) {
2044
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2045
		} else {
2046
			interface_setup_pppoe_reset_file($ppp['if']);
2047
		}
2048
	}
2049
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2050
	$i = 0;
2051
	while ($i < 3) {
2052
		sleep(10);
2053
		if (does_interface_exist($ppp['if'], true)) {
2054
			break;
2055
		}
2056
		$i++;
2057
	}
2058

    
2059
	/* Remove all temporary bogon IPv4 addresses */
2060
	if (is_array($tempaddr)) {
2061
		foreach ($tempaddr as $tempiface) {
2062
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2063
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2064
			}
2065
		}
2066
		unset ($tempaddr);
2067
	}
2068

    
2069
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2070
	/* We should be able to launch the right version for each modem */
2071
	/* We can also guess the mondev from the manufacturer */
2072
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2073
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2074
	foreach ($ports as $port) {
2075
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2076
			$mondev = substr(basename($port), 0, -1);
2077
			$devlist = glob("/dev/{$mondev}?");
2078
			$mondev = basename(end($devlist));
2079
		}
2080
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2081
			$mondev = substr(basename($port), 0, -1) . "1";
2082
		}
2083
		if ($mondev != '') {
2084
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2085
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2086
		}
2087
	}
2088

    
2089
	return 1;
2090
}
2091

    
2092
function interfaces_sync_setup() {
2093
	global $g, $config;
2094

    
2095
	if (isset($config['system']['developerspew'])) {
2096
		$mt = microtime();
2097
		echo "interfaces_sync_setup() being called $mt\n";
2098
	}
2099

    
2100
	if (platform_booting()) {
2101
		echo gettext("Configuring CARP settings...");
2102
		mute_kernel_msgs();
2103
	}
2104

    
2105
	/* suck in configuration items */
2106
	if ($config['hasync']) {
2107
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2108
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2109
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2110
	} else {
2111
		unset($pfsyncinterface);
2112
		unset($pfsyncenabled);
2113
	}
2114

    
2115
	set_sysctl(array(
2116
		"net.inet.carp.preempt" => "1",
2117
		"net.inet.carp.log" => "1")
2118
	);
2119

    
2120
	if (!empty($pfsyncinterface)) {
2121
		$carp_sync_int = get_real_interface($pfsyncinterface);
2122
	} else {
2123
		unset($carp_sync_int);
2124
	}
2125

    
2126
	/* setup pfsync interface */
2127
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2128
		if (is_ipaddr($pfsyncpeerip)) {
2129
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2130
		} else {
2131
			$syncpeer = "-syncpeer";
2132
		}
2133

    
2134
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2135
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2136

    
2137
		sleep(1);
2138

    
2139
		/* 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
2140
		 * for existing sessions.
2141
		 */
2142
		log_error(gettext("waiting for pfsync..."));
2143
		$i = 0;
2144
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2145
			$i++;
2146
			sleep(1);
2147
		}
2148
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2149
		log_error(gettext("Configuring CARP settings finalize..."));
2150
	} else {
2151
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2152
	}
2153

    
2154
	$carplist = get_configured_vip_list('all', VIP_CARP);
2155
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2156
		set_single_sysctl("net.inet.carp.allow", "1");
2157
	} else {
2158
		set_single_sysctl("net.inet.carp.allow", "0");
2159
	}
2160

    
2161
	if (platform_booting()) {
2162
		unmute_kernel_msgs();
2163
		echo gettext("done.") . "\n";
2164
	}
2165
}
2166

    
2167
function interface_proxyarp_configure($interface = "") {
2168
	global $config, $g;
2169
	if (isset($config['system']['developerspew'])) {
2170
		$mt = microtime();
2171
		echo "interface_proxyarp_configure() being called $mt\n";
2172
	}
2173

    
2174
	/* kill any running choparp */
2175
	if (empty($interface)) {
2176
		killbyname("choparp");
2177
	} else {
2178
		$vipif = get_real_interface($interface);
2179
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2180
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2181
		}
2182
	}
2183

    
2184
	$paa = array();
2185
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2186

    
2187
		/* group by interface */
2188
		foreach ($config['virtualip']['vip'] as $vipent) {
2189
			if ($vipent['mode'] === "proxyarp") {
2190
				if ($vipent['interface']) {
2191
					$proxyif = $vipent['interface'];
2192
				} else {
2193
					$proxyif = "wan";
2194
				}
2195

    
2196
				if (!empty($interface) && $interface != $proxyif) {
2197
					continue;
2198
				}
2199

    
2200
				if (!is_array($paa[$proxyif])) {
2201
					$paa[$proxyif] = array();
2202
				}
2203

    
2204
				$paa[$proxyif][] = $vipent;
2205
			}
2206
		}
2207
	}
2208

    
2209
	if (!empty($interface)) {
2210
		if (is_array($paa[$interface])) {
2211
			$paaifip = get_interface_ip($interface);
2212
			if (!is_ipaddr($paaifip)) {
2213
				return;
2214
			}
2215
			$args = get_real_interface($interface) . " auto";
2216
			foreach ($paa[$interface] as $paent) {
2217
				if (isset($paent['subnet'])) {
2218
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2219
				} else if (isset($paent['range'])) {
2220
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2221
				}
2222
			}
2223
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2224
		}
2225
	} else if (count($paa) > 0) {
2226
		foreach ($paa as $paif => $paents) {
2227
			$paaifip = get_interface_ip($paif);
2228
			if (!is_ipaddr($paaifip)) {
2229
				continue;
2230
			}
2231
			$args = get_real_interface($paif) . " auto";
2232
			foreach ($paents as $paent) {
2233
				if (isset($paent['subnet'])) {
2234
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2235
				} else if (isset($paent['range'])) {
2236
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2237
				}
2238
			}
2239
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2240
		}
2241
	}
2242
}
2243

    
2244
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2245
	global $g, $config;
2246

    
2247
	if (is_array($config['virtualip']['vip'])) {
2248
		foreach ($config['virtualip']['vip'] as $vip) {
2249

    
2250
			$iface = $vip['interface'];
2251
			if (substr($iface, 0, 4) == "_vip")
2252
				$iface = get_configured_vip_interface($vip['interface']);
2253
			if ($iface != $interface)
2254
				continue;
2255
			if ($type == VIP_CARP) {
2256
				if ($vip['mode'] != "carp")
2257
					continue;
2258
			} elseif ($type == VIP_IPALIAS) {
2259
				if ($vip['mode'] != "ipalias")
2260
					continue;
2261
			} else {
2262
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2263
					continue;
2264
			}
2265

    
2266
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2267
				interface_vip_bring_down($vip);
2268
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2269
				interface_vip_bring_down($vip);
2270
			else if ($inet == "all")
2271
				interface_vip_bring_down($vip);
2272
		}
2273
	}
2274
}
2275

    
2276
function interfaces_vips_configure($interface = "") {
2277
	global $g, $config;
2278
	if (isset($config['system']['developerspew'])) {
2279
		$mt = microtime();
2280
		echo "interfaces_vips_configure() being called $mt\n";
2281
	}
2282
	$paa = array();
2283
	if (is_array($config['virtualip']['vip'])) {
2284
		$carp_setuped = false;
2285
		$anyproxyarp = false;
2286
		foreach ($config['virtualip']['vip'] as $vip) {
2287
			switch ($vip['mode']) {
2288
				case "proxyarp":
2289
					/* nothing it is handled on interface_proxyarp_configure() */
2290
					if ($interface <> "" && $vip['interface'] <> $interface) {
2291
						continue;
2292
					}
2293
					$anyproxyarp = true;
2294
					break;
2295
				case "ipalias":
2296
					$iface = $vip['interface'];
2297
					if (substr($iface, 0, 4) == "_vip")
2298
						$iface = get_configured_vip_interface($vip['interface']);
2299
					if ($interface <> "" && $iface <> $interface) {
2300
						continue;
2301
					}
2302
					interface_ipalias_configure($vip);
2303
					break;
2304
				case "carp":
2305
					if ($interface <> "" && $vip['interface'] <> $interface) {
2306
						continue;
2307
					}
2308
					if ($carp_setuped == false) {
2309
						$carp_setuped = true;
2310
					}
2311
					interface_carp_configure($vip);
2312
					break;
2313
			}
2314
		}
2315
		if ($carp_setuped == true) {
2316
			interfaces_sync_setup();
2317
		}
2318
		if ($anyproxyarp == true) {
2319
			interface_proxyarp_configure();
2320
		}
2321
	}
2322
}
2323

    
2324
function interface_ipalias_configure(&$vip) {
2325
	global $config;
2326

    
2327
	if ($vip['mode'] != 'ipalias') {
2328
		return;
2329
	}
2330

    
2331
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2332
	if ($realif != "lo0") {
2333
		$if = convert_real_interface_to_friendly_interface_name($realif);
2334
		if (!isset($config['interfaces'][$if])) {
2335
			return;
2336
		}
2337

    
2338
		if (!isset($config['interfaces'][$if]['enable'])) {
2339
			return;
2340
		}
2341
	}
2342

    
2343
	$af = 'inet';
2344
	if (is_ipaddrv6($vip['subnet'])) {
2345
		$af = 'inet6';
2346
	}
2347
	$iface = $vip['interface'];
2348
	$vhid = '';
2349
	if (substr($vip['interface'], 0, 4) == "_vip") {
2350
		$carpvip = get_configured_vip($vip['interface']);
2351
		$iface = $carpvip['interface'];
2352
		$vhid = "vhid {$carpvip['vhid']}";
2353
	}
2354
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2355
	unset($iface, $af, $realif, $carpvip, $vhid);
2356
}
2357

    
2358
function interface_carp_configure(&$vip) {
2359
	global $config, $g;
2360
	if (isset($config['system']['developerspew'])) {
2361
		$mt = microtime();
2362
		echo "interface_carp_configure() being called $mt\n";
2363
	}
2364

    
2365
	if ($vip['mode'] != "carp") {
2366
		return;
2367
	}
2368

    
2369
	/* NOTE: Maybe its useless nowadays */
2370
	$realif = get_real_interface($vip['interface']);
2371
	if (!does_interface_exist($realif)) {
2372
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2373
		return;
2374
	}
2375

    
2376
	$vip_password = $vip['password'];
2377
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2378
	if ($vip['password'] != "") {
2379
		$password = " pass {$vip_password}";
2380
	}
2381

    
2382
	$advbase = "";
2383
	if (!empty($vip['advbase'])) {
2384
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2385
	}
2386

    
2387
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2388
	if ($carp_maintenancemode) {
2389
		$advskew = "advskew 254";
2390
	} else {
2391
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2392
	}
2393

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

    
2396
	if (is_ipaddrv4($vip['subnet'])) {
2397
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2398
	} else if (is_ipaddrv6($vip['subnet'])) {
2399
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2400
	}
2401

    
2402
	return $realif;
2403
}
2404

    
2405
function interface_wireless_clone($realif, $wlcfg) {
2406
	global $config, $g;
2407
	/*   Check to see if interface has been cloned as of yet.
2408
	 *   If it has not been cloned then go ahead and clone it.
2409
	 */
2410
	$needs_clone = false;
2411
	if (is_array($wlcfg['wireless'])) {
2412
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2413
	} else {
2414
		$wlcfg_mode = $wlcfg['mode'];
2415
	}
2416
	switch ($wlcfg_mode) {
2417
		case "hostap":
2418
			$mode = "wlanmode hostap";
2419
			break;
2420
		case "adhoc":
2421
			$mode = "wlanmode adhoc";
2422
			break;
2423
		default:
2424
			$mode = "";
2425
			break;
2426
	}
2427
	$baseif = interface_get_wireless_base($wlcfg['if']);
2428
	if (does_interface_exist($realif)) {
2429
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2430
		$ifconfig_str = implode($output);
2431
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2432
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2433
			$needs_clone = true;
2434
		}
2435
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2436
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2437
			$needs_clone = true;
2438
		}
2439
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2440
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2441
			$needs_clone = true;
2442
		}
2443
	} else {
2444
		$needs_clone = true;
2445
	}
2446

    
2447
	if ($needs_clone == true) {
2448
		/* remove previous instance if it exists */
2449
		if (does_interface_exist($realif)) {
2450
			pfSense_interface_destroy($realif);
2451
		}
2452

    
2453
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2454
		// Create the new wlan interface. FreeBSD returns the new interface name.
2455
		// example:  wlan2
2456
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2457
		if ($ret <> 0) {
2458
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2459
			return false;
2460
		}
2461
		$newif = trim($out[0]);
2462
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2463
		pfSense_interface_rename($newif, $realif);
2464
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2465
	}
2466
	return true;
2467
}
2468

    
2469
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2470
	global $config, $g;
2471

    
2472
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2473
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2474
				 'regdomain', 'regcountry', 'reglocation');
2475

    
2476
	if (!is_interface_wireless($ifcfg['if'])) {
2477
		return;
2478
	}
2479

    
2480
	$baseif = interface_get_wireless_base($ifcfg['if']);
2481

    
2482
	// Sync shared settings for assigned clones
2483
	$iflist = get_configured_interface_list(false, true);
2484
	foreach ($iflist as $if) {
2485
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2486
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2487
				foreach ($shared_settings as $setting) {
2488
					if ($sync_changes) {
2489
						if (isset($ifcfg['wireless'][$setting])) {
2490
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2491
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2492
							unset($config['interfaces'][$if]['wireless'][$setting]);
2493
						}
2494
					} else {
2495
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2496
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2497
						} else if (isset($ifcfg['wireless'][$setting])) {
2498
							unset($ifcfg['wireless'][$setting]);
2499
						}
2500
					}
2501
				}
2502
				if (!$sync_changes) {
2503
					break;
2504
				}
2505
			}
2506
		}
2507
	}
2508

    
2509
	// Read or write settings at shared area
2510
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2511
		foreach ($shared_settings as $setting) {
2512
			if ($sync_changes) {
2513
				if (isset($ifcfg['wireless'][$setting])) {
2514
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2515
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2516
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2517
				}
2518
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2519
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2520
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2521
				} else if (isset($ifcfg['wireless'][$setting])) {
2522
					unset($ifcfg['wireless'][$setting]);
2523
				}
2524
			}
2525
		}
2526
	}
2527

    
2528
	// Sync the mode on the clone creation page with the configured mode on the interface
2529
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2530
		foreach ($config['wireless']['clone'] as &$clone) {
2531
			if ($clone['cloneif'] == $ifcfg['if']) {
2532
				if ($sync_changes) {
2533
					$clone['mode'] = $ifcfg['wireless']['mode'];
2534
				} else {
2535
					$ifcfg['wireless']['mode'] = $clone['mode'];
2536
				}
2537
				break;
2538
			}
2539
		}
2540
		unset($clone);
2541
	}
2542
}
2543

    
2544
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2545
	global $config, $g;
2546

    
2547
	/*    open up a shell script that will be used to output the commands.
2548
	 *    since wireless is changing a lot, these series of commands are fragile
2549
	 *    and will sometimes need to be verified by a operator by executing the command
2550
	 *    and returning the output of the command to the developers for inspection.  please
2551
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2552
	 */
2553

    
2554
	// Remove script file
2555
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2556

    
2557
	// Clone wireless nic if needed.
2558
	interface_wireless_clone($if, $wl);
2559

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

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

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

    
2569
	/* set values for /path/program */
2570
	$hostapd = "/usr/sbin/hostapd";
2571
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2572
	$ifconfig = "/sbin/ifconfig";
2573
	$sysctl = "/sbin/sysctl";
2574
	$killall = "/usr/bin/killall";
2575

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

    
2578
	$wlcmd = array();
2579
	$wl_sysctl = array();
2580
	/* Set a/b/g standard */
2581
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2582
	/* skip mode entirely for "auto" */
2583
	if ($wlcfg['standard'] != "auto") {
2584
		$wlcmd[] = "mode " . escapeshellarg($standard);
2585
	}
2586

    
2587
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2588
	 * to prevent massive packet loss under certain conditions. */
2589
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2590
		$wlcmd[] = "-ampdu";
2591
	}
2592

    
2593
	/* Set ssid */
2594
	if ($wlcfg['ssid']) {
2595
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2596
	}
2597

    
2598
	/* Set 802.11g protection mode */
2599
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2600

    
2601
	/* set wireless channel value */
2602
	if (isset($wlcfg['channel'])) {
2603
		if ($wlcfg['channel'] == "0") {
2604
			$wlcmd[] = "channel any";
2605
		} else {
2606
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2607
		}
2608
	}
2609

    
2610
	/* Set antenna diversity value */
2611
	if (isset($wlcfg['diversity'])) {
2612
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2613
	}
2614

    
2615
	/* Set txantenna value */
2616
	if (isset($wlcfg['txantenna'])) {
2617
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2618
	}
2619

    
2620
	/* Set rxantenna value */
2621
	if (isset($wlcfg['rxantenna'])) {
2622
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2623
	}
2624

    
2625
	/* set Distance value */
2626
	if ($wlcfg['distance']) {
2627
		$distance = escapeshellarg($wlcfg['distance']);
2628
	}
2629

    
2630
	/* Set wireless hostap mode */
2631
	if ($wlcfg['mode'] == "hostap") {
2632
		$wlcmd[] = "mediaopt hostap";
2633
	} else {
2634
		$wlcmd[] = "-mediaopt hostap";
2635
	}
2636

    
2637
	/* Set wireless adhoc mode */
2638
	if ($wlcfg['mode'] == "adhoc") {
2639
		$wlcmd[] = "mediaopt adhoc";
2640
	} else {
2641
		$wlcmd[] = "-mediaopt adhoc";
2642
	}
2643

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

    
2646
	/* handle hide ssid option */
2647
	if (isset($wlcfg['hidessid']['enable'])) {
2648
		$wlcmd[] = "hidessid";
2649
	} else {
2650
		$wlcmd[] = "-hidessid";
2651
	}
2652

    
2653
	/* handle pureg (802.11g) only option */
2654
	if (isset($wlcfg['pureg']['enable'])) {
2655
		$wlcmd[] = "mode 11g pureg";
2656
	} else {
2657
		$wlcmd[] = "-pureg";
2658
	}
2659

    
2660
	/* handle puren (802.11n) only option */
2661
	if (isset($wlcfg['puren']['enable'])) {
2662
		$wlcmd[] = "puren";
2663
	} else {
2664
		$wlcmd[] = "-puren";
2665
	}
2666

    
2667
	/* enable apbridge option */
2668
	if (isset($wlcfg['apbridge']['enable'])) {
2669
		$wlcmd[] = "apbridge";
2670
	} else {
2671
		$wlcmd[] = "-apbridge";
2672
	}
2673

    
2674
	/* handle turbo option */
2675
	if (isset($wlcfg['turbo']['enable'])) {
2676
		$wlcmd[] = "mediaopt turbo";
2677
	} else {
2678
		$wlcmd[] = "-mediaopt turbo";
2679
	}
2680

    
2681
	/* handle txpower setting */
2682
	// or don't. this has issues at the moment.
2683
	/*
2684
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2685
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2686
	}*/
2687

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

    
2695
	/* Enable wpa if it's configured. No WEP support anymore. */
2696
	if (isset($wlcfg['wpa']['enable'])) {
2697
		$wlcmd[] = "authmode wpa wepmode off ";
2698
	} else {
2699
		$wlcmd[] = "authmode open wepmode off ";
2700
	}
2701

    
2702
	kill_hostapd($if);
2703
	mwexec(kill_wpasupplicant("{$if}"));
2704

    
2705
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2706

    
2707
	switch ($wlcfg['mode']) {
2708
		case 'bss':
2709
			if (isset($wlcfg['wpa']['enable'])) {
2710
				$wpa .= <<<EOD
2711
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2712
ctrl_interface_group=0
2713
ap_scan=1
2714
#fast_reauth=1
2715
network={
2716
ssid="{$wlcfg['ssid']}"
2717
scan_ssid=1
2718
priority=5
2719
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2720
psk="{$wlcfg['wpa']['passphrase']}"
2721
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2722
group={$wlcfg['wpa']['wpa_pairwise']}
2723
}
2724
EOD;
2725

    
2726
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2727
				unset($wpa);
2728
			}
2729
			break;
2730
		case 'hostap':
2731
			if (!empty($wlcfg['wpa']['passphrase'])) {
2732
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2733
			} else {
2734
				$wpa_passphrase = "";
2735
			}
2736
			if (isset($wlcfg['wpa']['enable'])) {
2737
				$wpa .= <<<EOD
2738
interface={$if}
2739
driver=bsd
2740
logger_syslog=-1
2741
logger_syslog_level=0
2742
logger_stdout=-1
2743
logger_stdout_level=0
2744
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2745
ctrl_interface={$g['varrun_path']}/hostapd
2746
ctrl_interface_group=wheel
2747
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2748
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2749
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2750
ssid={$wlcfg['ssid']}
2751
debug={$wlcfg['wpa']['debug_mode']}
2752
wpa={$wlcfg['wpa']['wpa_mode']}
2753
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2754
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2755
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2756
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2757
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2758
{$wpa_passphrase}
2759

    
2760
EOD;
2761

    
2762
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2763
					$wpa .= <<<EOD
2764
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2765
rsn_preauth=1
2766
rsn_preauth_interfaces={$if}
2767

    
2768
EOD;
2769
				}
2770
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2771
					$wpa .= "ieee8021x=1\n";
2772

    
2773
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2774
						$auth_server_port = "1812";
2775
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2776
							$auth_server_port = intval($wlcfg['auth_server_port']);
2777
						}
2778
						$wpa .= <<<EOD
2779

    
2780
auth_server_addr={$wlcfg['auth_server_addr']}
2781
auth_server_port={$auth_server_port}
2782
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2783

    
2784
EOD;
2785
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2786
							$auth_server_port2 = "1812";
2787
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2788
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2789
							}
2790

    
2791
							$wpa .= <<<EOD
2792
auth_server_addr={$wlcfg['auth_server_addr2']}
2793
auth_server_port={$auth_server_port2}
2794
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2795

    
2796
EOD;
2797
						}
2798
					}
2799
				}
2800

    
2801
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2802
				unset($wpa);
2803
			}
2804
			break;
2805
	}
2806

    
2807
	/*
2808
	 *    all variables are set, lets start up everything
2809
	 */
2810

    
2811
	$baseif = interface_get_wireless_base($if);
2812
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2813
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2814

    
2815
	/* set sysctls for the wireless interface */
2816
	if (!empty($wl_sysctl)) {
2817
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2818
		foreach ($wl_sysctl as $wl_sysctl_line) {
2819
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2820
		}
2821
	}
2822

    
2823
	/* set ack timers according to users preference (if he/she has any) */
2824
	if ($distance) {
2825
		fwrite($fd_set, "# Enable ATH distance settings\n");
2826
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2827
	}
2828

    
2829
	if (isset($wlcfg['wpa']['enable'])) {
2830
		if ($wlcfg['mode'] == "bss") {
2831
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2832
		}
2833
		if ($wlcfg['mode'] == "hostap") {
2834
			/* add line to script to restore old mac to make hostapd happy */
2835
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2836
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2837
				$if_curmac = get_interface_mac($if);
2838
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
2839
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2840
						" link " . escapeshellarg($if_oldmac) . "\n");
2841
				}
2842
			}
2843

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

    
2846
			/* add line to script to restore spoofed mac after running hostapd */
2847
			if ($wl['spoofmac']) {
2848
				$if_curmac = get_interface_mac($if);
2849
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
2850
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2851
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
2852
				}
2853
			}
2854
		}
2855
	}
2856

    
2857
	fclose($fd_set);
2858

    
2859
	/* Making sure regulatory settings have actually changed
2860
	 * before applying, because changing them requires bringing
2861
	 * down all wireless networks on the interface. */
2862
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2863
	$ifconfig_str = implode($output);
2864
	unset($output);
2865
	$reg_changing = false;
2866

    
2867
	/* special case for the debug country code */
2868
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2869
		$reg_changing = true;
2870
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2871
		$reg_changing = true;
2872
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2873
		$reg_changing = true;
2874
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2875
		$reg_changing = true;
2876
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2877
		$reg_changing = true;
2878
	}
2879

    
2880
	if ($reg_changing) {
2881
		/* set regulatory domain */
2882
		if ($wlcfg['regdomain']) {
2883
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2884
		}
2885

    
2886
		/* set country */
2887
		if ($wlcfg['regcountry']) {
2888
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2889
		}
2890

    
2891
		/* set location */
2892
		if ($wlcfg['reglocation']) {
2893
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2894
		}
2895

    
2896
		$wlregcmd_args = implode(" ", $wlregcmd);
2897

    
2898
		/* build a complete list of the wireless clones for this interface */
2899
		$clone_list = array();
2900
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2901
			$clone_list[] = interface_get_wireless_clone($baseif);
2902
		}
2903
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2904
			foreach ($config['wireless']['clone'] as $clone) {
2905
				if ($clone['if'] == $baseif) {
2906
					$clone_list[] = $clone['cloneif'];
2907
				}
2908
			}
2909
		}
2910

    
2911
		/* find which clones are up and bring them down */
2912
		$clones_up = array();
2913
		foreach ($clone_list as $clone_if) {
2914
			$clone_status = pfSense_get_interface_addresses($clone_if);
2915
			if ($clone_status['status'] == 'up') {
2916
				$clones_up[] = $clone_if;
2917
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2918
			}
2919
		}
2920

    
2921
		/* apply the regulatory settings */
2922
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2923
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2924

    
2925
		/* bring the clones back up that were previously up */
2926
		foreach ($clones_up as $clone_if) {
2927
			interfaces_bring_up($clone_if);
2928

    
2929
			/*
2930
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2931
			 * is in infrastructure mode, and WPA is enabled.
2932
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2933
			 */
2934
			if ($clone_if != $if) {
2935
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2936
				if ((!empty($friendly_if)) &&
2937
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2938
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2939
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2940
				}
2941
			}
2942
		}
2943
	}
2944

    
2945
	/* The mode must be specified in a separate command before ifconfig
2946
	 * will allow the mode and channel at the same time in the next.
2947
	 * Only do this for AP mode as this breaks client mode (PR 198680).
2948
	 */
2949
	if ($wlcfg['mode'] == "hostap") {
2950
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2951
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2952
	}
2953

    
2954
	/* configure wireless */
2955
	$wlcmd_args = implode(" ", $wlcmd);
2956
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2957
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2958
	/* Bring the interface up only after setting up all the other parameters. */
2959
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
2960
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
2961
	fclose($wlan_setup_log);
2962

    
2963
	unset($wlcmd_args, $wlcmd);
2964

    
2965

    
2966
	sleep(1);
2967
	/* execute hostapd and wpa_supplicant if required in shell */
2968
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2969

    
2970
	return 0;
2971

    
2972
}
2973

    
2974
function kill_hostapd($interface) {
2975
	global $g;
2976

    
2977
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2978
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2979
	}
2980
}
2981

    
2982
function kill_wpasupplicant($interface) {
2983
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2984
}
2985

    
2986
function find_dhclient_process($interface) {
2987
	if ($interface) {
2988
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2989
	} else {
2990
		$pid = 0;
2991
	}
2992

    
2993
	return intval($pid);
2994
}
2995

    
2996
function kill_dhclient_process($interface) {
2997
	if (empty($interface) || !does_interface_exist($interface)) {
2998
		return;
2999
	}
3000

    
3001
	$i = 0;
3002
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3003
		/* 3rd time make it die for sure */
3004
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3005
		posix_kill($pid, $sig);
3006
		sleep(1);
3007
		$i++;
3008
	}
3009
	unset($i);
3010
}
3011

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

    
3015
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3016
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3017
	} else {
3018
		return(false);
3019
	}
3020

    
3021
	return intval($pid);
3022
}
3023

    
3024
function kill_dhcp6client_process($interface) {
3025
	if (empty($interface) || !does_interface_exist($interface)) {
3026
		return;
3027
	}
3028

    
3029
	if (($pid = find_dhcp6c_process($interface)) != 0) {
3030
		mwexec("kill -9 {$pid}");
3031
		sleep(1);
3032
	}
3033
}
3034

    
3035
function interface_virtual_create($interface) {
3036
	global $config;
3037

    
3038
	if (strstr($interface, "_vlan")) {
3039
		interfaces_vlan_configure($vlan);
3040
	} else if (substr($interface, 0, 3) == "gre") {
3041
		interfaces_gre_configure(0, $interface);
3042
	} else if (substr($interface, 0, 3) == "gif") {
3043
		interfaces_gif_configure(0, $interface);
3044
	} else if (substr($interface, 0, 5) == "ovpns") {
3045
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3046
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3047
				if ($interface == "ovpns{$server['vpnid']}") {
3048
					if (!function_exists('openvpn_resync')) {
3049
						require_once('openvpn.inc');
3050
					}
3051
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3052
					openvpn_resync('server', $server);
3053
				}
3054
			}
3055
			unset($server);
3056
		}
3057
	} else if (substr($interface, 0, 5) == "ovpnc") {
3058
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3059
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3060
				if ($interface == "ovpnc{$client['vpnid']}") {
3061
					if (!function_exists('openvpn_resync')) {
3062
						require_once('openvpn.inc');
3063
					}
3064
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3065
					openvpn_resync('client', $client);
3066
				}
3067
			}
3068
			unset($client);
3069
		}
3070
	} else if (substr($interface, 0, 4) == "lagg") {
3071
		interfaces_lagg_configure($interface);
3072
	} else if (substr($interface, 0, 6) == "bridge") {
3073
		interfaces_bridge_configure(0, $interface);
3074
	}
3075
}
3076

    
3077
function interface_vlan_mtu_configured($iface) {
3078
	global $config;
3079

    
3080
	$mtu = 0;
3081
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3082
		foreach ($config['vlans']['vlan'] as $vlan) {
3083

    
3084
			if ($vlan['vlanif'] != $iface)
3085
				continue;
3086

    
3087
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3088
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3089
				/* VLAN MTU */
3090
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3091
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3092
				/* Parent MTU */
3093
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3094
			}
3095
		}
3096
	}
3097

    
3098
	return $mtu;
3099
}
3100

    
3101
function interface_mtu_wanted_for_pppoe($realif) {
3102
	global $config;
3103

    
3104
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3105
		return 0;
3106

    
3107
	$mtu = 0;
3108
	foreach ($config['ppps']['ppp'] as $ppp) {
3109
		if ($ppp['type'] != "pppoe") {
3110
			continue;
3111
		}
3112

    
3113
		$mtus = array();
3114
		if (!empty($ppp['mtu'])) {
3115
			$mtus = explode(',', $ppp['mtu']);
3116
		}
3117
		$ports = explode(',', $ppp['ports']);
3118

    
3119
		foreach ($ports as $pid => $port) {
3120
			$parentifa = get_parent_interface($port);
3121
			$parentif = $parentifa[0];
3122
			if ($parentif != $realif)
3123
				continue;
3124

    
3125
			// there is an MTU configured on the port in question
3126
			if (!empty($mtus[$pid])) {
3127
				$mtu = intval($mtus[$pid]) + 8;
3128
			// or use the MTU configured on the interface ...
3129
			} elseif (is_array($config['interfaces'])) {
3130
				foreach ($config['interfaces'] as $interface) {
3131
					if ($interface['if'] == $ppp['if'] &&
3132
					    !empty($interface['mtu'])) {
3133
						$mtu = intval($interface['mtu']) + 8;
3134
						break;
3135
					}
3136
				}
3137
			}
3138
		}
3139
	}
3140

    
3141
	return $mtu;
3142
}
3143

    
3144
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3145
	global $config, $g;
3146
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3147
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3148

    
3149
	$wancfg = $config['interfaces'][$interface];
3150

    
3151
	if (!isset($wancfg['enable'])) {
3152
		return;
3153
	}
3154

    
3155
	$realif = get_real_interface($interface);
3156
	$realhwif_array = get_parent_interface($interface);
3157
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3158
	$realhwif = $realhwif_array[0];
3159

    
3160
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3161
		/* remove all IPv4 and IPv6 addresses */
3162
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3163
		if (is_array($tmpifaces)) {
3164
			foreach ($tmpifaces as $tmpiface) {
3165
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3166
					if (!is_linklocal($tmpiface)) {
3167
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3168
					}
3169
				} else {
3170
					if (is_subnetv4($tmpiface)) {
3171
						$tmpip = explode('/', $tmpiface);
3172
						$tmpip = $tmpip[0];
3173
					} else {
3174
						$tmpip = $tmpiface;
3175
					}
3176
					pfSense_interface_deladdress($realif, $tmpip);
3177
				}
3178
			}
3179
		}
3180

    
3181
		/* only bring down the interface when both v4 and v6 are set to NONE */
3182
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3183
			interface_bring_down($interface);
3184
		}
3185
	}
3186

    
3187
	$interface_to_check = $realif;
3188
	if (interface_isppp_type($interface)) {
3189
		$interface_to_check = $realhwif;
3190
	}
3191

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

    
3197
	/* Disable Accepting router advertisements unless specifically requested */
3198
	if ($g['debug']) {
3199
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3200
	}
3201
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3202

    
3203
	/* wireless configuration? */
3204
	if (is_array($wancfg['wireless'])) {
3205
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3206
	}
3207

    
3208
	$mac = get_interface_mac($realhwif);
3209
	/*
3210
	 * Don't try to reapply the spoofed MAC if it's already applied.
3211
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3212
	 * the interface config again, which attempts to spoof the MAC again,
3213
	 * which cycles the link again...
3214
	 */
3215
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3216
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3217
			" link " . escapeshellarg($wancfg['spoofmac']));
3218
	} else {
3219

    
3220
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3221
			/*   this is not a valid mac address.  generate a
3222
			 *   temporary mac address so the machine can get online.
3223
			 */
3224
			echo gettext("Generating new MAC address.");
3225
			$random_mac = generate_random_mac_address();
3226
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3227
				" link " . escapeshellarg($random_mac));
3228
			$wancfg['spoofmac'] = $random_mac;
3229
			write_config();
3230
			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");
3231
		}
3232
	}
3233

    
3234
	/* media */
3235
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3236
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3237
		if ($wancfg['media']) {
3238
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3239
		}
3240
		if ($wancfg['mediaopt']) {
3241
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3242
		}
3243
		mwexec($cmd);
3244
	}
3245

    
3246
	/* Apply hw offloading policies as configured */
3247
	enable_hardware_offloading($interface);
3248

    
3249
	/* invalidate interface/ip/sn cache */
3250
	get_interface_arr(true);
3251
	unset($interface_ip_arr_cache[$realif]);
3252
	unset($interface_sn_arr_cache[$realif]);
3253
	unset($interface_ipv6_arr_cache[$realif]);
3254
	unset($interface_snv6_arr_cache[$realif]);
3255

    
3256
	$tunnelif = substr($realif, 0, 3);
3257

    
3258
	$mtuif = $realif;
3259
	$mtuhwif = $realhwif;
3260

    
3261
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3262
	if (interface_isppp_type($interface)) {
3263
		$mtuif = $realhwif;
3264
		$mtuhwif_array = get_parent_interface($mtuif);
3265
		$mtuhwif = $mtuhwif_array[0];
3266
	}
3267

    
3268
	$wantedmtu = 0;
3269
	if (is_array($config['interfaces'])) {
3270
		foreach ($config['interfaces'] as $tmpinterface) {
3271
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3272
				$wantedmtu = $tmpinterface['mtu'];
3273
				break;
3274
			}
3275
		}
3276
	}
3277

    
3278
	/* MTU is not specified for interface, try the pppoe settings. */
3279
	if ($wantedmtu == 0) {
3280
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3281
	}
3282
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3283
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3284
	}
3285

    
3286
	/* Set the MTU to 1500 if no explicit MTU configured. */
3287
	if ($wantedmtu == 0) {
3288
		$wantedmtu = 1500; /* Default */
3289
	}
3290

    
3291
	if (stristr($mtuif, "_vlan")) {
3292
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3293
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3294
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3295
			if ($wancfg['mtu'] > $parentmtu) {
3296
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3297
			}
3298
		}
3299

    
3300
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3301

    
3302
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3303
			$configuredmtu = $parentmtu;
3304
		if ($configuredmtu != 0)
3305
			$mtu = $configuredmtu;
3306
		else
3307
			$mtu = $wantedmtu;
3308

    
3309
		/* Set the parent MTU. */
3310
		if (get_interface_mtu($mtuhwif) < $mtu)
3311
			set_interface_mtu($mtuhwif, $mtu);
3312
		/* Set the VLAN MTU. */
3313
		if (get_interface_mtu($mtuif) != $mtu)
3314
			set_interface_mtu($mtuif, $mtu);
3315
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3316
		/* LAGG interface must be destroyed and re-created to change MTU */
3317
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3318
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3319
				foreach ($config['laggs']['lagg'] as $lagg) {
3320
					if ($lagg['laggif'] == $mtuif) {
3321
						interface_lagg_configure($lagg);
3322
						break;
3323
					}
3324
				}
3325
			}
3326
		}
3327
	} else {
3328
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3329
			pfSense_interface_mtu($mtuif, $wantedmtu);
3330
		}
3331
	}
3332
	/* XXX: What about gre/gif/.. ? */
3333

    
3334
	if (does_interface_exist($wancfg['if'])) {
3335
		interfaces_bring_up($wancfg['if']);
3336
	}
3337

    
3338
	switch ($wancfg['ipaddr']) {
3339
		case 'dhcp':
3340
			interface_dhcp_configure($interface);
3341
			break;
3342
		case 'pppoe':
3343
		case 'l2tp':
3344
		case 'pptp':
3345
		case 'ppp':
3346
			interface_ppps_configure($interface);
3347
			break;
3348
		default:
3349
			/* XXX: Kludge for now related to #3280 */
3350
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3351
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3352
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3353
				}
3354
			}
3355
			break;
3356
	}
3357

    
3358
	switch ($wancfg['ipaddrv6']) {
3359
		case 'slaac':
3360
		case 'dhcp6':
3361
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3362
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3363
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3364
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3365
				interface_dhcpv6_configure($interface, $wancfg);
3366
			}
3367
			break;
3368
		case '6rd':
3369
			interface_6rd_configure($interface, $wancfg);
3370
			break;
3371
		case '6to4':
3372
			interface_6to4_configure($interface, $wancfg);
3373
			break;
3374
		case 'track6':
3375
			interface_track6_configure($interface, $wancfg, $linkupevent);
3376
			break;
3377
		default:
3378
			/* XXX: Kludge for now related to #3280 */
3379
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3380
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3381
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3382
					// FIXME: Add IPv6 Support to the pfSense module
3383
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3384
				}
3385
			}
3386
			break;
3387
	}
3388

    
3389
	interface_netgraph_needed($interface);
3390

    
3391
	if (!platform_booting()) {
3392
		link_interface_to_vips($interface, "update");
3393

    
3394
		if ($tunnelif != 'gre') {
3395
			unset($gre);
3396
			$gre = link_interface_to_gre($interface);
3397
			if (!empty($gre)) {
3398
				array_walk($gre, 'interface_gre_configure');
3399
			}
3400
		}
3401

    
3402
		if ($tunnelif != 'gif') {
3403
			unset($gif);
3404
			$gif = link_interface_to_gif ($interface);
3405
			if (!empty($gif)) {
3406
				array_walk($gif, 'interface_gif_configure');
3407
			}
3408
		}
3409

    
3410
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3411
			unset($bridgetmp);
3412
			$bridgetmp = link_interface_to_bridge($interface);
3413
			if (!empty($bridgetmp)) {
3414
				interface_bridge_add_member($bridgetmp, $realif);
3415
			}
3416
		}
3417

    
3418
		$grouptmp = link_interface_to_group($interface);
3419
		if (!empty($grouptmp)) {
3420
			array_walk($grouptmp, 'interface_group_add_member');
3421
		}
3422

    
3423
		if ($interface == "lan") {
3424
			/* make new hosts file */
3425
			system_hosts_generate();
3426
		}
3427

    
3428
		if ($reloadall == true) {
3429

    
3430
			/* reconfigure static routes (kernel may have deleted them) */
3431
			system_routing_configure($interface);
3432

    
3433
			/* reload ipsec tunnels */
3434
			send_event("service reload ipsecdns");
3435

    
3436
			if (isset($config['dnsmasq']['enable'])) {
3437
				services_dnsmasq_configure();
3438
			}
3439

    
3440
			if (isset($config['unbound']['enable'])) {
3441
				services_unbound_configure();
3442
			}
3443

    
3444
			/* update dyndns */
3445
			send_event("service reload dyndns {$interface}");
3446

    
3447
			/* reload captive portal */
3448
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3449
				require_once('captiveportal.inc');
3450
			}
3451
			captiveportal_init_rules_byinterface($interface);
3452
		}
3453
	}
3454

    
3455
	interfaces_staticarp_configure($interface);
3456
	return 0;
3457
}
3458

    
3459
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3460
	global $config, $g;
3461

    
3462
	if (!is_array($wancfg)) {
3463
		return;
3464
	}
3465

    
3466
	if (!isset($wancfg['enable'])) {
3467
		return;
3468
	}
3469

    
3470
	/* If the interface is not configured via another, exit */
3471
	if (empty($wancfg['track6-interface'])) {
3472
		return;
3473
	}
3474

    
3475
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3476
	$realif = get_real_interface($interface);
3477
	$linklocal = find_interface_ipv6_ll($realif, true);
3478
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3479
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3480
	}
3481
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3482
	/* XXX: Probably should remove? */
3483
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3484

    
3485
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3486
	if (!isset($trackcfg['enable'])) {
3487
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3488
		return;
3489
	}
3490

    
3491
	switch ($trackcfg['ipaddrv6']) {
3492
		case "6to4":
3493
			if ($g['debug']) {
3494
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3495
			}
3496
			interface_track6_6to4_configure($interface, $wancfg);
3497
			break;
3498
		case "6rd":
3499
			if ($g['debug']) {
3500
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3501
			}
3502
			interface_track6_6rd_configure($interface, $wancfg);
3503
			break;
3504
		case "dhcp6":
3505
			if ($linkupevent == true) {
3506
				/*
3507
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3508
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3509
				 *
3510
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3511
				 */
3512
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3513
				$pidv6 = find_dhcp6c_process($parentrealif);
3514
				if ($pidv6) {
3515
					posix_kill($pidv6, SIGHUP);
3516
				}
3517
			}
3518
			break;
3519
	}
3520

    
3521
	if ($linkupevent == false && !platform_booting()) {
3522
		if (!function_exists('services_dhcpd_configure')) {
3523
			require_once("services.inc");
3524
		}
3525

    
3526
		/* restart dns servers (defering dhcpd reload) */
3527
		if (isset($config['unbound']['enable'])) {
3528
			services_unbound_configure(false);
3529
		}
3530
		if (isset($config['dnsmasq']['enable'])) {
3531
			services_dnsmasq_configure(false);
3532
		}
3533

    
3534
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3535
		services_dhcpd_configure("inet6");
3536
	}
3537

    
3538
	return 0;
3539
}
3540

    
3541
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3542
	global $config, $g;
3543
	global $interface_ipv6_arr_cache;
3544
	global $interface_snv6_arr_cache;
3545

    
3546
	if (!is_array($lancfg)) {
3547
		return;
3548
	}
3549

    
3550
	/* If the interface is not configured via another, exit */
3551
	if (empty($lancfg['track6-interface'])) {
3552
		return;
3553
	}
3554

    
3555
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3556
	if (empty($wancfg)) {
3557
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3558
		return;
3559
	}
3560

    
3561
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3562
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3563
		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']));
3564
		return;
3565
	}
3566
	$hexwanv4 = return_hex_ipv4($ip4address);
3567

    
3568
	/* create the long prefix notation for math, save the prefix length */
3569
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3570
	$rd6prefixlen = $rd6prefix[1];
3571
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3572

    
3573
	/* binary presentation of the prefix for all 128 bits. */
3574
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3575

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

    
3581
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3582
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3583
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3584
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3585
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3586
	/* fill the rest out with zeros */
3587
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3588

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

    
3592
	$lanif = get_real_interface($interface);
3593
	$oip = find_interface_ipv6($lanif);
3594
	if (is_ipaddrv6($oip)) {
3595
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3596
	}
3597
	unset($interface_ipv6_arr_cache[$lanif]);
3598
	unset($interface_snv6_arr_cache[$lanif]);
3599
	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));
3600
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3601

    
3602
	return 0;
3603
}
3604

    
3605
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3606
	global $config, $g;
3607
	global $interface_ipv6_arr_cache;
3608
	global $interface_snv6_arr_cache;
3609

    
3610
	if (!is_array($lancfg)) {
3611
		return;
3612
	}
3613

    
3614
	/* If the interface is not configured via another, exit */
3615
	if (empty($lancfg['track6-interface'])) {
3616
		return;
3617
	}
3618

    
3619
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3620
	if (empty($wancfg)) {
3621
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3622
		return;
3623
	}
3624

    
3625
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3626
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3627
		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']));
3628
		return;
3629
	}
3630
	$hexwanv4 = return_hex_ipv4($ip4address);
3631

    
3632
	/* create the long prefix notation for math, save the prefix length */
3633
	$sixto4prefix = "2002::";
3634
	$sixto4prefixlen = 16;
3635
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3636

    
3637
	/* binary presentation of the prefix for all 128 bits. */
3638
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3639

    
3640
	/* just save the left prefix length bits */
3641
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3642
	/* add the v4 address */
3643
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3644
	/* add the custom prefix id */
3645
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3646
	/* fill the rest out with zeros */
3647
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3648

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

    
3652
	$lanif = get_real_interface($interface);
3653
	$oip = find_interface_ipv6($lanif);
3654
	if (is_ipaddrv6($oip)) {
3655
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3656
	}
3657
	unset($interface_ipv6_arr_cache[$lanif]);
3658
	unset($interface_snv6_arr_cache[$lanif]);
3659
	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));
3660
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3661

    
3662
	return 0;
3663
}
3664

    
3665
function interface_6rd_configure($interface = "wan", $wancfg) {
3666
	global $config, $g;
3667

    
3668
	/* because this is a tunnel interface we can only function
3669
	 *	with a public IPv4 address on the interface */
3670

    
3671
	if (!is_array($wancfg)) {
3672
		return;
3673
	}
3674

    
3675
	if (!is_module_loaded('if_stf.ko')) {
3676
		mwexec('/sbin/kldload if_stf.ko');
3677
	}
3678

    
3679
	$wanif = get_real_interface($interface);
3680
	$ip4address = find_interface_ip($wanif);
3681
	if (!is_ipaddrv4($ip4address)) {
3682
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3683
		return false;
3684
	}
3685
	$hexwanv4 = return_hex_ipv4($ip4address);
3686

    
3687
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3688
		$wancfg['prefix-6rd-v4plen'] = 0;
3689
	}
3690

    
3691
	/* create the long prefix notation for math, save the prefix length */
3692
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3693
	$rd6prefixlen = $rd6prefix[1];
3694
	$brgw = explode('.', $wancfg['gateway-6rd']);
3695
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
3696
	$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);
3697
	if (strlen($rd6brgw) < 128) {
3698
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3699
	}
3700
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
3701
	unset($brgw);
3702
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3703

    
3704
	/* binary presentation of the prefix for all 128 bits. */
3705
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3706

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

    
3714
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3715
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3716

    
3717

    
3718
	/* XXX: need to extend to support variable prefix size for v4 */
3719
	if (!is_module_loaded("if_stf")) {
3720
		mwexec("/sbin/kldload if_stf.ko");
3721
	}
3722
	$stfiface = "{$interface}_stf";
3723
	if (does_interface_exist($stfiface)) {
3724
		pfSense_interface_destroy($stfiface);
3725
	}
3726
	$tmpstfiface = pfSense_interface_create("stf");
3727
	pfSense_interface_rename($tmpstfiface, $stfiface);
3728
	pfSense_interface_flags($stfiface, IFF_LINK2);
3729
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3730
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3731
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3732
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3733
	}
3734
	if ($g['debug']) {
3735
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3736
	}
3737

    
3738
	/* write out a default router file */
3739
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3740
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3741

    
3742
	$ip4gateway = get_interface_gateway($interface);
3743
	if (is_ipaddrv4($ip4gateway)) {
3744
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
3745
	}
3746

    
3747
	/* configure dependent interfaces */
3748
	if (!platform_booting()) {
3749
		link_interface_to_track6($interface, "update");
3750
	}
3751

    
3752
	return 0;
3753
}
3754

    
3755
function interface_6to4_configure($interface = "wan", $wancfg) {
3756
	global $config, $g;
3757

    
3758
	/* because this is a tunnel interface we can only function
3759
	 *	with a public IPv4 address on the interface */
3760

    
3761
	if (!is_array($wancfg)) {
3762
		return;
3763
	}
3764

    
3765
	$wanif = get_real_interface($interface);
3766
	$ip4address = find_interface_ip($wanif);
3767
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3768
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3769
		return false;
3770
	}
3771

    
3772
	/* create the long prefix notation for math, save the prefix length */
3773
	$stfprefixlen = 16;
3774
	$stfprefix = Net_IPv6::uncompress("2002::");
3775
	$stfarr = explode(":", $stfprefix);
3776
	$v4prefixlen = "0";
3777

    
3778
	/* we need the hex form of the interface IPv4 address */
3779
	$ip4arr = explode(".", $ip4address);
3780
	$hexwanv4 = "";
3781
	foreach ($ip4arr as $octet) {
3782
		$hexwanv4 .= sprintf("%02x", $octet);
3783
	}
3784

    
3785
	/* we need the hex form of the broker IPv4 address */
3786
	$ip4arr = explode(".", "192.88.99.1");
3787
	$hexbrv4 = "";
3788
	foreach ($ip4arr as $octet) {
3789
		$hexbrv4 .= sprintf("%02x", $octet);
3790
	}
3791

    
3792
	/* binary presentation of the prefix for all 128 bits. */
3793
	$stfprefixbin = "";
3794
	foreach ($stfarr as $element) {
3795
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3796
	}
3797
	/* just save the left prefix length bits */
3798
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3799

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

    
3804
	/* for the local subnet too. */
3805
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3806
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3807

    
3808
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3809
	$stfbrarr = array();
3810
	$stfbrbinarr = array();
3811
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3812
	foreach ($stfbrbinarr as $bin) {
3813
		$stfbrarr[] = dechex(bindec($bin));
3814
	}
3815
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3816

    
3817
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3818
	$stflanarr = array();
3819
	$stflanbinarr = array();
3820
	$stflanbinarr = str_split($stflanbin, 16);
3821
	foreach ($stflanbinarr as $bin) {
3822
		$stflanarr[] = dechex(bindec($bin));
3823
	}
3824
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3825
	$stflanarr[7] = 1;
3826
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3827

    
3828
	/* setup the stf interface */
3829
	if (!is_module_loaded("if_stf")) {
3830
		mwexec("/sbin/kldload if_stf.ko");
3831
	}
3832
	$stfiface = "{$interface}_stf";
3833
	if (does_interface_exist($stfiface)) {
3834
		pfSense_interface_destroy($stfiface);
3835
	}
3836
	$tmpstfiface = pfSense_interface_create("stf");
3837
	pfSense_interface_rename($tmpstfiface, $stfiface);
3838
	pfSense_interface_flags($stfiface, IFF_LINK2);
3839
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3840

    
3841
	if ($g['debug']) {
3842
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3843
	}
3844

    
3845
	/* write out a default router file */
3846
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3847
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3848

    
3849
	$ip4gateway = get_interface_gateway($interface);
3850
	if (is_ipaddrv4($ip4gateway)) {
3851
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
3852
	}
3853

    
3854
	if (!platform_booting()) {
3855
		link_interface_to_track6($interface, "update");
3856
	}
3857

    
3858
	return 0;
3859
}
3860

    
3861
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3862
	global $config, $g;
3863

    
3864
	if (!is_array($wancfg)) {
3865
		return;
3866
	}
3867

    
3868
	$wanif = get_real_interface($interface, "inet6");
3869
	$dhcp6cconf = "";
3870

    
3871
	if ($wancfg['adv_dhcp6_config_file_override']) {
3872
		// DHCP6 Config File Override
3873
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3874
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3875
		// DHCP6 Config File Advanced
3876
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3877
	} else {
3878
		// DHCP6 Config File Basic
3879
		$dhcp6cconf .= "interface {$wanif} {\n";
3880

    
3881
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3882
		if ($wancfg['ipaddrv6'] == "slaac") {
3883
			$dhcp6cconf .= "\tinformation-only;\n";
3884
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3885
			$dhcp6cconf .= "\trequest domain-name;\n";
3886
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3887
			$dhcp6cconf .= "};\n";
3888
		} else {
3889
			$trackiflist = array();
3890
			$iflist = link_interface_to_track6($interface);
3891
			foreach ($iflist as $ifname => $ifcfg) {
3892
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3893
					$trackiflist[$ifname] = $ifcfg;
3894
				}
3895
			}
3896

    
3897
			/* skip address request if this is set */
3898
			if (!isset($wancfg['dhcp6prefixonly'])) {
3899
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3900
			}
3901
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3902
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3903
			}
3904

    
3905
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3906
			$dhcp6cconf .= "\trequest domain-name;\n";
3907
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3908
			$dhcp6cconf .= "};\n";
3909

    
3910
			if (!isset($wancfg['dhcp6prefixonly'])) {
3911
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3912
			}
3913

    
3914
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3915
				/* Setup the prefix delegation */
3916
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3917
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3918
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3919
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3920
				}
3921
				foreach ($trackiflist as $friendly => $ifcfg) {
3922
					if ($g['debug']) {
3923
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3924
					}
3925
					$realif = get_real_interface($friendly);
3926
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3927
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3928
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3929
					$dhcp6cconf .= "\t};\n";
3930
				}
3931
				unset($preflen, $iflist, $ifcfg, $ifname);
3932
				$dhcp6cconf .= "};\n";
3933
			}
3934
			unset($trackiflist);
3935
		}
3936
	}
3937

    
3938
	/* wide-dhcp6c works for now. */
3939
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3940
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3941
		unset($dhcp6cconf);
3942
		return 1;
3943
	}
3944
	unset($dhcp6cconf);
3945

    
3946
	$dhcp6cscript = "#!/bin/sh\n";
3947
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3948
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3949
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3950
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3951
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3952
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3953
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3954
		unset($dhcp6cscript);
3955
		return 1;
3956
	}
3957
	unset($dhcp6cscript);
3958
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3959

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

    
3966
	/* non ipoe Process */
3967
	if (!isset($wancfg['dhcp6withoutra'])) {
3968
		$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3969
		$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3970
		$rtsoldscript .= "\t/bin/sleep 1\n";
3971
		$rtsoldscript .= "fi\n";
3972
	} else {
3973
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
3974
		$rtsoldscript .= "/bin/sleep 1\n";
3975
	}
3976
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3977

    
3978
	/* add the start of dhcp6c to the rtsold script if we are going to wait for ra */
3979
	if (!isset($wancfg['dhcp6withoutra'])) {
3980
		$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3981
		$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3982
	}
3983
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3984
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3985
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
3986
		unset($rtsoldscript);
3987
		return 1;
3988
	}
3989
	unset($rtsoldscript);
3990
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3991

    
3992
	/* accept router advertisements for this interface */
3993
	log_error("Accept router advertisements on interface {$wanif} ");
3994
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3995

    
3996
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3997
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3998
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3999
		sleep(2);
4000
	}
4001

    
4002
	/* start dhcp6c here if we don't want to wait for ra */
4003
	if (isset($wancfg['dhcp6withoutra'])) {
4004
		kill_dhcp6client_process($wanif);
4005

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

    
4011
	/* NOTE: will be called from rtsold invoked script
4012
	 * link_interface_to_track6($interface, "update");
4013
	 */
4014

    
4015
	return 0;
4016
}
4017

    
4018
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4019
	global $g;
4020

    
4021
	$send_options = "";
4022
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4023
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4024
		foreach ($options as $option) {
4025
			$send_options .= "\tsend " . trim($option) . ";\n";
4026
		}
4027
	}
4028

    
4029
	$request_options = "";
4030
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4031
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4032
		foreach ($options as $option) {
4033
			$request_options .= "\trequest " . trim($option) . ";\n";
4034
		}
4035
	}
4036

    
4037
	$information_only = "";
4038
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4039
		$information_only = "\tinformation-only;\n";
4040
	}
4041

    
4042
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4043
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4044
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4045
	}
4046

    
4047
	$interface_statement  = "interface";
4048
	$interface_statement .= " {$wanif}";
4049
	$interface_statement .= " {\n";
4050
	$interface_statement .= "$send_options";
4051
	$interface_statement .= "$request_options";
4052
	$interface_statement .= "$information_only";
4053
	$interface_statement .= "$script";
4054
	$interface_statement .= "};\n";
4055

    
4056
	$id_assoc_statement_address = "";
4057
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4058
		$id_assoc_statement_address .= "id-assoc";
4059
		$id_assoc_statement_address .= " na";
4060
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4061
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4062
		}
4063
		$id_assoc_statement_address .= " { ";
4064

    
4065
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4066
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4067
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4068
			$id_assoc_statement_address .= "\n\taddress";
4069
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4070
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4071
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4072
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4073
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4074
			}
4075
			$id_assoc_statement_address .= ";\n";
4076
		}
4077

    
4078
		$id_assoc_statement_address .= "};\n";
4079
	}
4080

    
4081
	$id_assoc_statement_prefix = "";
4082
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4083
		$id_assoc_statement_prefix .= "id-assoc";
4084
		$id_assoc_statement_prefix .= " pd";
4085
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4086
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4087
		}
4088
		$id_assoc_statement_prefix .= " { ";
4089

    
4090
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4091
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4092
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4093
			$id_assoc_statement_prefix .= "\n\tprefix";
4094
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4095
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4096
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4097
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4098
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4099
			}
4100
			$id_assoc_statement_prefix .= ";";
4101
		}
4102

    
4103
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4104
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4105
			$id_assoc_statement_prefix .= " {$wanif}";
4106
			$id_assoc_statement_prefix .= " {\n";
4107
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4108
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4109
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4110
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4111
			}
4112
			$id_assoc_statement_prefix .= "\t};";
4113
		}
4114

    
4115
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4116
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4117
			$id_assoc_statement_prefix .= "\n";
4118
		}
4119

    
4120
		$id_assoc_statement_prefix .= "};\n";
4121
	}
4122

    
4123
	$authentication_statement = "";
4124
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4125
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4126
		$authentication_statement .= "authentication";
4127
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4128
		$authentication_statement .= " {\n";
4129
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4130
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4131
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4132
		}
4133
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4134
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4135
		}
4136
		$authentication_statement .= "};\n";
4137
	}
4138

    
4139
	$key_info_statement = "";
4140
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4141
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4142
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4143
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4144
		$key_info_statement .= "keyinfo";
4145
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4146
		$key_info_statement .= " {\n";
4147
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4148
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4149
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4150
		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'])) {
4151
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4152
		}
4153
		$key_info_statement .= "};\n";
4154
	}
4155

    
4156
	$dhcp6cconf  = $interface_statement;
4157
	$dhcp6cconf .= $id_assoc_statement_address;
4158
	$dhcp6cconf .= $id_assoc_statement_prefix;
4159
	$dhcp6cconf .= $authentication_statement;
4160
	$dhcp6cconf .= $key_info_statement;
4161

    
4162
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4163

    
4164
	return $dhcp6cconf;
4165
}
4166

    
4167

    
4168
function DHCP6_Config_File_Override($wancfg, $wanif) {
4169

    
4170
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4171

    
4172
	if ($dhcp6cconf === false) {
4173
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4174
		return '';
4175
	} else {
4176
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4177
	}
4178
}
4179

    
4180

    
4181
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4182

    
4183
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4184

    
4185
	return $dhcp6cconf;
4186
}
4187

    
4188

    
4189
function interface_dhcp_configure($interface = "wan") {
4190
	global $config, $g;
4191

    
4192
	$wancfg = $config['interfaces'][$interface];
4193
	$wanif = $wancfg['if'];
4194
	if (empty($wancfg)) {
4195
		$wancfg = array();
4196
	}
4197

    
4198
	/* generate dhclient_wan.conf */
4199
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4200
	if (!$fd) {
4201
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4202
		return 1;
4203
	}
4204

    
4205
	if ($wancfg['dhcphostname']) {
4206
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4207
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4208
	} else {
4209
		$dhclientconf_hostname = "";
4210
	}
4211

    
4212
	$wanif = get_real_interface($interface);
4213
	if (empty($wanif)) {
4214
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4215
		return 0;
4216
	}
4217
	$dhclientconf = "";
4218

    
4219
	$dhclientconf .= <<<EOD
4220
interface "{$wanif}" {
4221
timeout 60;
4222
retry 15;
4223
select-timeout 0;
4224
initial-interval 1;
4225
	{$dhclientconf_hostname}
4226
	script "/usr/local/sbin/pfSense-dhclient-script";
4227
EOD;
4228

    
4229
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4230
		$dhclientconf .= <<<EOD
4231

    
4232
	reject {$wancfg['dhcprejectfrom']};
4233
EOD;
4234
	}
4235
	$dhclientconf .= <<<EOD
4236

    
4237
}
4238

    
4239
EOD;
4240

    
4241
	// DHCP Config File Advanced
4242
	if ($wancfg['adv_dhcp_config_advanced']) {
4243
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4244
	}
4245

    
4246
	if (is_ipaddr($wancfg['alias-address'])) {
4247
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4248
		$dhclientconf .= <<<EOD
4249
alias {
4250
	interface "{$wanif}";
4251
	fixed-address {$wancfg['alias-address']};
4252
	option subnet-mask {$subnetmask};
4253
}
4254

    
4255
EOD;
4256
	}
4257

    
4258
	// DHCP Config File Override
4259
	if ($wancfg['adv_dhcp_config_file_override']) {
4260
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4261
	}
4262

    
4263
	fwrite($fd, $dhclientconf);
4264
	fclose($fd);
4265

    
4266
	/* bring wan interface up before starting dhclient */
4267
	if ($wanif) {
4268
		interfaces_bring_up($wanif);
4269
	} else {
4270
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4271
	}
4272

    
4273
	/* Make sure dhclient is not running */
4274
	kill_dhclient_process($wanif);
4275

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

    
4279
	return 0;
4280
}
4281

    
4282
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4283

    
4284
	$hostname = "";
4285
	if ($wancfg['dhcphostname'] != '') {
4286
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4287
	}
4288

    
4289
	/* DHCP Protocol Timings */
4290
	$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");
4291
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4292
		$pt_variable = "{$Protocol_Timing}";
4293
		${$pt_variable} = "";
4294
		if ($wancfg[$Protocol_Timing] != "") {
4295
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4296
		}
4297
	}
4298

    
4299
	$send_options = "";
4300
	if ($wancfg['adv_dhcp_send_options'] != '') {
4301
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4302
		foreach ($options as $option) {
4303
			$send_options .= "\tsend " . trim($option) . ";\n";
4304
		}
4305
	}
4306

    
4307
	$request_options = "";
4308
	if ($wancfg['adv_dhcp_request_options'] != '') {
4309
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4310
	}
4311

    
4312
	$required_options = "";
4313
	if ($wancfg['adv_dhcp_required_options'] != '') {
4314
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4315
	}
4316

    
4317
	$option_modifiers = "";
4318
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4319
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4320
		foreach ($modifiers as $modifier) {
4321
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4322
		}
4323
	}
4324

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

    
4348
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4349

    
4350
	return $dhclientconf;
4351
}
4352

    
4353
function DHCP_Config_Option_Split($option_string) {
4354
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4355
	return $matches ? $matches[0] : [];
4356
}
4357

    
4358
function DHCP_Config_File_Override($wancfg, $wanif) {
4359

    
4360
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4361

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

    
4370

    
4371
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4372

    
4373
	/* Apply Interface Substitutions */
4374
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4375

    
4376
	/* Apply Hostname Substitutions */
4377
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4378

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

    
4385
	/* Apply MAC Address Substitutions */
4386
	foreach ($various_mac_types as $various_mac_type) {
4387
		foreach ($various_mac_cases as $various_mac_case) {
4388
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4389

    
4390
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4391
				if ($res !== false) {
4392

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

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

    
4413
					/* MAC Address Delimiter Substitutions */
4414
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4415

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

    
4423
	return $dhclientconf;
4424
}
4425

    
4426
function interfaces_group_setup() {
4427
	global $config;
4428

    
4429
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4430
		return;
4431
	}
4432

    
4433
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4434
		interface_group_setup($groupar);
4435
	}
4436

    
4437
	return;
4438
}
4439

    
4440
function interface_group_setup(&$groupname /* The parameter is an array */) {
4441
	global $config;
4442

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

    
4454
	return;
4455
}
4456

    
4457
function is_interface_group($if) {
4458
	global $config;
4459

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

    
4468
	return false;
4469
}
4470

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

    
4478
/* COMPAT Function */
4479
function convert_friendly_interface_to_real_interface_name($interface) {
4480
	return get_real_interface($interface);
4481
}
4482

    
4483
/* COMPAT Function */
4484
function get_real_wan_interface($interface = "wan") {
4485
	return get_real_interface($interface);
4486
}
4487

    
4488
/* COMPAT Function */
4489
function get_current_wan_address($interface = "wan") {
4490
	return get_interface_ip($interface);
4491
}
4492

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

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

    
4503
	foreach ($ifdescrs as $if => $ifname) {
4504
		if ($if == $interface || $ifname['if'] == $interface) {
4505
			return $if;
4506
		}
4507

    
4508
		if (get_real_interface($if) == $interface) {
4509
			return $if;
4510
		}
4511

    
4512
		if ($checkparent == false) {
4513
			continue;
4514
		}
4515

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

    
4526
	if ($interface == "enc0") {
4527
		return 'IPsec';
4528
	}
4529
}
4530

    
4531
/* attempt to resolve interface to friendly descr */
4532
function convert_friendly_interface_to_friendly_descr($interface) {
4533
	global $config;
4534

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

    
4588
	return $ifdesc;
4589
}
4590

    
4591
function convert_real_interface_to_friendly_descr($interface) {
4592

    
4593
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4594

    
4595
	if (!empty($ifdesc)) {
4596
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4597
	}
4598

    
4599
	return $interface;
4600
}
4601

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

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

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

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

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

    
4679
	if (empty($parents)) {
4680
		$parents[0] = $realif;
4681
	}
4682

    
4683
	return $parents;
4684
}
4685

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

    
4694
	$realif = get_parent_interface($interface);
4695

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

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

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

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

    
4731
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4732
	global $config, $g;
4733

    
4734
	$wanif = NULL;
4735

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

    
4778
			if (empty($config['interfaces'][$interface])) {
4779
				break;
4780
			}
4781

    
4782
			$cfg = &$config['interfaces'][$interface];
4783

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

    
4840
	return $wanif;
4841
}
4842

    
4843
/* Guess the physical interface by providing a IP address */
4844
function guess_interface_from_ip($ipaddress) {
4845

    
4846
	$family = '';
4847
	if (is_ipaddrv4($ipaddress)) {
4848
		$family = 'inet';
4849
	}
4850
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4851
		$family = 'inet6';
4852
	}
4853

    
4854
	if (empty($family)) {
4855
		return false;
4856
	}
4857

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

    
4866
	return false;
4867
}
4868

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

    
4878
	$isv6ip = is_ipaddrv6($ip);
4879

    
4880
	/* if list */
4881
	$ifdescrs = get_configured_interface_list();
4882

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

    
4901
	return false;
4902
}
4903

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

    
4911
	if (!is_array($config['virtualip']['vip'])) {
4912
		return false;
4913
	}
4914
	if (!is_ipaddr($ip)) {
4915
		return false;
4916
	}
4917

    
4918
	$isv6ip = is_ipaddrv6($ip);
4919

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

    
4940
function link_interface_to_track6($int, $action = "") {
4941
	global $config;
4942

    
4943
	if (empty($int)) {
4944
		return;
4945
	}
4946

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

    
4965
function interface_find_child_cfgmtu($realiface) {
4966
	global $config;
4967

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

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

    
5041
	return $mtu;
5042
}
5043

    
5044
function link_interface_to_vlans($int, $action = "") {
5045
	global $config;
5046

    
5047
	if (empty($int)) {
5048
		return;
5049
	}
5050

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

    
5068
function link_interface_to_qinqs($int, $action = "") {
5069
	global $config;
5070

    
5071
	if (empty($int)) {
5072
		return;
5073
	}
5074

    
5075
	if (is_array($config['qinqs']['qinqentry'])) {
5076
		$ifaces = array();
5077
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5078
			if ($int == $qinq['if']) {
5079
				if ($action == "update") {
5080
					interfaces_bring_up($int);
5081
				} else {
5082
					$ifaces[$qinq['tag']] = $qinq;
5083
				}
5084
			}
5085
		}
5086
		if (!empty($ifaces)) {
5087
			return $ifaces;
5088
		}
5089
	}
5090
}
5091

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

    
5095
	$updatevips = false;
5096
	if (is_array($config['virtualip']['vip'])) {
5097
		$result = array();
5098
		foreach ($config['virtualip']['vip'] as $vip) {
5099
			if (substr($vip['interface'], 0, 4) == "_vip") {
5100
				$iface = get_configured_vip_interface($vip['interface']);
5101
			} else {
5102
				$iface = $vip['interface'];
5103
			}
5104
			if ($int != $iface) {
5105
				continue;
5106
			}
5107
			if ($action == "update") {
5108
				$updatevips = true;
5109
			} else {
5110
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5111
				    substr($vip['interface'], 0, 4) == "_vip") {
5112
					$result[] = $vip;
5113
				}
5114
			}
5115
		}
5116
		if ($updatevips === true) {
5117
			interfaces_vips_configure($int);
5118
		}
5119
		return $result;
5120
	}
5121

    
5122
	return NULL;
5123
}
5124

    
5125
/****f* interfaces/link_interface_to_bridge
5126
 * NAME
5127
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5128
 * INPUTS
5129
 *   $ip
5130
 * RESULT
5131
 *   bridge[0-99]
5132
 ******/
5133
function link_interface_to_bridge($int) {
5134
	global $config;
5135

    
5136
	if (is_array($config['bridges']['bridged'])) {
5137
		foreach ($config['bridges']['bridged'] as $bridge) {
5138
			if (in_array($int, explode(',', $bridge['members']))) {
5139
				return "{$bridge['bridgeif']}";
5140
			}
5141
		}
5142
	}
5143
}
5144

    
5145
function link_interface_to_group($int) {
5146
	global $config;
5147

    
5148
	$result = array();
5149

    
5150
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5151
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5152
			if (in_array($int, explode(" ", $group['members']))) {
5153
				$result[$group['ifname']] = $int;
5154
			}
5155
		}
5156
	}
5157

    
5158
	return $result;
5159
}
5160

    
5161
function link_interface_to_gre($interface) {
5162
	global $config;
5163

    
5164
	$result = array();
5165

    
5166
	if (is_array($config['gres']['gre'])) {
5167
		foreach ($config['gres']['gre'] as $gre) {
5168
			if ($gre['if'] == $interface) {
5169
				$result[] = $gre;
5170
			}
5171
		}
5172
	}
5173

    
5174
	return $result;
5175
}
5176

    
5177
function link_interface_to_gif($interface) {
5178
	global $config;
5179

    
5180
	$result = array();
5181

    
5182
	if (is_array($config['gifs']['gif'])) {
5183
		foreach ($config['gifs']['gif'] as $gif) {
5184
			if ($gif['if'] == $interface) {
5185
				$result[] = $gif;
5186
			}
5187
		}
5188
	}
5189

    
5190
	return $result;
5191
}
5192

    
5193
/*
5194
 * find_interface_ip($interface): return the interface ip (first found)
5195
 */
5196
function find_interface_ip($interface, $flush = false) {
5197
	global $interface_ip_arr_cache;
5198
	global $interface_sn_arr_cache;
5199

    
5200
	$interface = str_replace("\n", "", $interface);
5201

    
5202
	if (!does_interface_exist($interface)) {
5203
		return;
5204
	}
5205

    
5206
	/* Setup IP cache */
5207
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5208
		$ifinfo = pfSense_get_interface_addresses($interface);
5209
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5210
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5211
	}
5212

    
5213
	return $interface_ip_arr_cache[$interface];
5214
}
5215

    
5216
/*
5217
 * find_interface_ipv6($interface): return the interface ip (first found)
5218
 */
5219
function find_interface_ipv6($interface, $flush = false) {
5220
	global $interface_ipv6_arr_cache;
5221
	global $interface_snv6_arr_cache;
5222
	global $config;
5223

    
5224
	$interface = trim($interface);
5225
	$interface = get_real_interface($interface);
5226

    
5227
	if (!does_interface_exist($interface)) {
5228
		return;
5229
	}
5230

    
5231
	/* Setup IP cache */
5232
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5233
		$ifinfo = pfSense_get_interface_addresses($interface);
5234
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5235
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5236
	}
5237

    
5238
	return $interface_ipv6_arr_cache[$interface];
5239
}
5240

    
5241
/*
5242
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5243
 */
5244
function find_interface_ipv6_ll($interface, $flush = false) {
5245
	global $interface_llv6_arr_cache;
5246
	global $config;
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_llv6_arr_cache[$interface]) or $flush) {
5256
		$ifinfo = pfSense_getall_interface_addresses($interface);
5257
		foreach ($ifinfo as $line) {
5258
			if (strstr($line, ":")) {
5259
				$parts = explode("/", $line);
5260
				if (is_linklocal($parts[0])) {
5261
					$ifinfo['linklocal'] = $parts[0];
5262
				}
5263
			}
5264
		}
5265
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5266
	}
5267
	return $interface_llv6_arr_cache[$interface];
5268
}
5269

    
5270
function find_interface_subnet($interface, $flush = false) {
5271
	global $interface_sn_arr_cache;
5272
	global $interface_ip_arr_cache;
5273

    
5274
	$interface = str_replace("\n", "", $interface);
5275
	if (does_interface_exist($interface) == false) {
5276
		return;
5277
	}
5278

    
5279
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5280
		$ifinfo = pfSense_get_interface_addresses($interface);
5281
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5282
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5283
	}
5284

    
5285
	return $interface_sn_arr_cache[$interface];
5286
}
5287

    
5288
function find_interface_subnetv6($interface, $flush = false) {
5289
	global $interface_snv6_arr_cache;
5290
	global $interface_ipv6_arr_cache;
5291

    
5292
	$interface = str_replace("\n", "", $interface);
5293
	if (does_interface_exist($interface) == false) {
5294
		return;
5295
	}
5296

    
5297
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5298
		$ifinfo = pfSense_get_interface_addresses($interface);
5299
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5300
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5301
	}
5302

    
5303
	return $interface_snv6_arr_cache[$interface];
5304
}
5305

    
5306
function ip_in_interface_alias_subnet($interface, $ipalias) {
5307
	global $config;
5308

    
5309
	if (empty($interface) || !is_ipaddr($ipalias)) {
5310
		return false;
5311
	}
5312
	if (is_array($config['virtualip']['vip'])) {
5313
		foreach ($config['virtualip']['vip'] as $vip) {
5314
			switch ($vip['mode']) {
5315
				case "ipalias":
5316
					if ($vip['interface'] <> $interface) {
5317
						break;
5318
					}
5319
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5320
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5321
						return true;
5322
					}
5323
					break;
5324
			}
5325
		}
5326
	}
5327

    
5328
	return false;
5329
}
5330

    
5331
function get_possible_listen_ips($include_ipv6_link_local=false) {
5332

    
5333
	$interfaces = get_configured_interface_with_descr();
5334
	foreach ($interfaces as $iface => $ifacename) {
5335
		if ($include_ipv6_link_local) {
5336
			/* This is to avoid going though added ll below */
5337
			if (substr($iface, 0, 5) == '_lloc') {
5338
				continue;
5339
			}
5340
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5341
			if (!empty($llip)) {
5342
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5343
			}
5344
		}
5345
	}
5346
	$viplist = get_configured_vip_list();
5347
	foreach ($viplist as $vip => $address) {
5348
		$interfaces[$vip] = $address;
5349
		if (get_vip_descr($address)) {
5350
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5351
		}
5352
	}
5353

    
5354
	$interfaces['lo0'] = 'Localhost';
5355

    
5356
	return $interfaces;
5357
}
5358

    
5359
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5360
	global $config;
5361

    
5362
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5363
	foreach (array('server', 'client') as $mode) {
5364
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5365
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5366
				if (!isset($setting['disable'])) {
5367
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5368
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5369
				}
5370
			}
5371
		}
5372
	}
5373
	return $sourceips;
5374
}
5375

    
5376
function get_interface_ip($interface = "wan") {
5377

    
5378
	if (substr($interface, 0, 4) == '_vip') {
5379
		return get_configured_vip_ipv4($interface);
5380
	} else if (substr($interface, 0, 5) == '_lloc') {
5381
		/* No link-local address for v4. */
5382
		return null;
5383
	}
5384

    
5385
	$realif = get_failover_interface($interface, 'inet');
5386
	if (!$realif) {
5387
		return null;
5388
	}
5389

    
5390
	if (substr($realif, 0, 4) == '_vip') {
5391
		return get_configured_vip_ipv4($realif);
5392
	} else if (substr($realif, 0, 5) == '_lloc') {
5393
		/* No link-local address for v4. */
5394
		return null;
5395
	}
5396

    
5397
	if (is_array($config['interfaces'][$interface]) &&
5398
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5399
		return ($config['interfaces'][$interface]['ipaddr']);
5400
	}
5401

    
5402
	/*
5403
	 * Beaware that find_interface_ip() is our last option, it will
5404
	 * return the first IP it find on interface, not necessarily the
5405
	 * main IP address.
5406
	 */
5407
	$curip = find_interface_ip($realif);
5408
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5409
		return $curip;
5410
	} else {
5411
		return null;
5412
	}
5413
}
5414

    
5415
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5416
	global $config;
5417

    
5418
	if (substr($interface, 0, 4) == '_vip') {
5419
		return get_configured_vip_ipv6($interface);
5420
	} else if (substr($interface, 0, 5) == '_lloc') {
5421
		return get_interface_linklocal($interface);
5422
	}
5423

    
5424
	$realif = get_failover_interface($interface, 'inet6');
5425
	if (!$realif) {
5426
		return null;
5427
	}
5428

    
5429
	if (substr($realif, 0, 4) == '_vip') {
5430
		return get_configured_vip_ipv6($realif);
5431
	} else if (substr($realif, 0, 5) == '_lloc') {
5432
		return get_interface_linklocal($realif);
5433
	}
5434

    
5435
	if (is_array($config['interfaces'][$interface])) {
5436
		switch ($config['interfaces'][$interface]['ipaddr']) {
5437
			case 'pppoe':
5438
			case 'l2tp':
5439
			case 'pptp':
5440
			case 'ppp':
5441
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5442
					$realif = get_real_interface($interface, 'inet6', false);
5443
				}
5444
				break;
5445
		}
5446
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5447
			return ($config['interfaces'][$interface]['ipaddrv6']);
5448
		}
5449
	}
5450

    
5451
	/*
5452
	 * Beaware that find_interface_ip() is our last option, it will
5453
	 * return the first IP it find on interface, not necessarily the
5454
	 * main IP address.
5455
	 */
5456
	$curip = find_interface_ipv6($realif, $flush);
5457
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5458
		return $curip;
5459
	} else {
5460
		/*
5461
		 * NOTE: On the case when only the prefix is requested,
5462
		 * the communication on WAN will be done over link-local.
5463
		 */
5464
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5465
			$curip = find_interface_ipv6_ll($realif, $flush);
5466
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5467
				return $curip;
5468
			}
5469
		}
5470
	}
5471
	return null;
5472
}
5473

    
5474
function get_interface_linklocal($interface = "wan") {
5475

    
5476
	$realif = get_failover_interface($interface, 'inet6');
5477
	if (!$realif) {
5478
		return null;
5479
	}
5480

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

    
5487
	$curip = find_interface_ipv6_ll($realif);
5488
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5489
		return $curip;
5490
	} else {
5491
		return null;
5492
	}
5493
}
5494

    
5495
function get_interface_subnet($interface = "wan") {
5496

    
5497
	if (substr($interface, 0, 4) == '_vip') {
5498
		return (get_configured_vip_subnetv4($interface));
5499
	}
5500

    
5501
	$realif = get_real_interface($interface);
5502
	if (!$realif) {
5503
		return (NULL);
5504
	}
5505

    
5506
	$cursn = find_interface_subnet($realif);
5507
	if (!empty($cursn)) {
5508
		return ($cursn);
5509
	}
5510

    
5511
	return (NULL);
5512
}
5513

    
5514
function get_interface_subnetv6($interface = "wan") {
5515

    
5516
	if (substr($interface, 0, 4) == '_vip') {
5517
		return (get_configured_vip_subnetv6($interface));
5518
	} else if (substr($interface, 0, 5) == '_lloc') {
5519
		$interface = substr($interface, 5);
5520
	}
5521

    
5522
	$realif = get_real_interface($interface, 'inet6');
5523
	if (!$realif) {
5524
		return (NULL);
5525
	}
5526

    
5527
	$cursn = find_interface_subnetv6($realif);
5528
	if (!empty($cursn)) {
5529
		return ($cursn);
5530
	}
5531

    
5532
	return (NULL);
5533
}
5534

    
5535
/* return outside interfaces with a gateway */
5536
function get_interfaces_with_gateway() {
5537
	global $config;
5538

    
5539
	$ints = array();
5540

    
5541
	/* loop interfaces, check config for outbound */
5542
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5543
		switch ($ifname['ipaddr']) {
5544
			case "dhcp":
5545
			case "pppoe":
5546
			case "pptp":
5547
			case "l2tp":
5548
			case "ppp":
5549
				$ints[$ifdescr] = $ifdescr;
5550
				break;
5551
			default:
5552
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5553
				    !empty($ifname['gateway'])) {
5554
					$ints[$ifdescr] = $ifdescr;
5555
				}
5556
				break;
5557
		}
5558
	}
5559
	return $ints;
5560
}
5561

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

    
5566
	if (!empty($config['interfaces'][$friendly])) {
5567
		$ifname = &$config['interfaces'][$friendly];
5568
		switch ($ifname['ipaddr']) {
5569
			case "dhcp":
5570
			case "pppoe":
5571
			case "pptp":
5572
			case "l2tp":
5573
			case "ppp":
5574
				return true;
5575
			break;
5576
			default:
5577
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5578
					return true;
5579
				}
5580
				$tunnelif = substr($ifname['if'], 0, 3);
5581
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5582
					if (find_interface_ip($ifname['if'])) {
5583
						return true;
5584
					}
5585
				}
5586
				if (!empty($ifname['gateway'])) {
5587
					return true;
5588
				}
5589
			break;
5590
		}
5591
	}
5592

    
5593
	return false;
5594
}
5595

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

    
5600
	if (!empty($config['interfaces'][$friendly])) {
5601
		$ifname = &$config['interfaces'][$friendly];
5602
		switch ($ifname['ipaddrv6']) {
5603
			case "slaac":
5604
			case "dhcp6":
5605
			case "6to4":
5606
			case "6rd":
5607
				return true;
5608
				break;
5609
			default:
5610
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5611
					return true;
5612
				}
5613
				$tunnelif = substr($ifname['if'], 0, 3);
5614
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5615
					if (find_interface_ipv6($ifname['if'])) {
5616
						return true;
5617
					}
5618
				}
5619
				if (!empty($ifname['gatewayv6'])) {
5620
					return true;
5621
				}
5622
				break;
5623
		}
5624
	}
5625

    
5626
	return false;
5627
}
5628

    
5629
/****f* interfaces/is_altq_capable
5630
 * NAME
5631
 *   is_altq_capable - Test if interface is capable of using ALTQ
5632
 * INPUTS
5633
 *   $int            - string containing interface name
5634
 * RESULT
5635
 *   boolean         - true or false
5636
 ******/
5637

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

    
5652
	$int_family = remove_ifindex($int);
5653

    
5654
	if (in_array($int_family, $capable)) {
5655
		return true;
5656
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5657
		return true;
5658
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5659
		return true;
5660
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5661
		return true;
5662
	} else {
5663
		return false;
5664
	}
5665
}
5666

    
5667
/****f* interfaces/is_interface_wireless
5668
 * NAME
5669
 *   is_interface_wireless - Returns if an interface is wireless
5670
 * RESULT
5671
 *   $tmp       - Returns if an interface is wireless
5672
 ******/
5673
function is_interface_wireless($interface) {
5674
	global $config, $g;
5675

    
5676
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5677
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5678
		if (preg_match($g['wireless_regex'], $interface)) {
5679
			if (isset($config['interfaces'][$friendly])) {
5680
				$config['interfaces'][$friendly]['wireless'] = array();
5681
			}
5682
			return true;
5683
		}
5684
		return false;
5685
	} else {
5686
		return true;
5687
	}
5688
}
5689

    
5690
function get_wireless_modes($interface) {
5691
	/* return wireless modes and channels */
5692
	$wireless_modes = array();
5693

    
5694
	$cloned_interface = get_real_interface($interface);
5695

    
5696
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5697
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5698
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5699
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5700

    
5701
		$interface_channels = "";
5702
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5703
		$interface_channel_count = count($interface_channels);
5704

    
5705
		$c = 0;
5706
		while ($c < $interface_channel_count) {
5707
			$channel_line = explode(",", $interface_channels["$c"]);
5708
			$wireless_mode = trim($channel_line[0]);
5709
			$wireless_channel = trim($channel_line[1]);
5710
			if (trim($wireless_mode) != "") {
5711
				/* if we only have 11g also set 11b channels */
5712
				if ($wireless_mode == "11g") {
5713
					if (!isset($wireless_modes["11b"])) {
5714
						$wireless_modes["11b"] = array();
5715
					}
5716
				} else if ($wireless_mode == "11g ht") {
5717
					if (!isset($wireless_modes["11b"])) {
5718
						$wireless_modes["11b"] = array();
5719
					}
5720
					if (!isset($wireless_modes["11g"])) {
5721
						$wireless_modes["11g"] = array();
5722
					}
5723
					$wireless_mode = "11ng";
5724
				} else if ($wireless_mode == "11a ht") {
5725
					if (!isset($wireless_modes["11a"])) {
5726
						$wireless_modes["11a"] = array();
5727
					}
5728
					$wireless_mode = "11na";
5729
				}
5730
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5731
			}
5732
			$c++;
5733
		}
5734
	}
5735
	return($wireless_modes);
5736
}
5737

    
5738
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5739
function get_wireless_channel_info($interface) {
5740
	$wireless_channels = array();
5741

    
5742
	$cloned_interface = get_real_interface($interface);
5743

    
5744
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5745
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5746
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5747
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5748

    
5749
		$interface_channels = "";
5750
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5751

    
5752
		foreach ($interface_channels as $channel_line) {
5753
			$channel_line = explode(",", $channel_line);
5754
			if (!isset($wireless_channels[$channel_line[0]])) {
5755
				$wireless_channels[$channel_line[0]] = $channel_line;
5756
			}
5757
		}
5758
	}
5759
	return($wireless_channels);
5760
}
5761

    
5762
function set_interface_mtu($interface, $mtu) {
5763

    
5764
	/* LAGG interface must be destroyed and re-created to change MTU */
5765
	if (substr($interface, 0, 4) == 'lagg') {
5766
		if (isset($config['laggs']['lagg']) &&
5767
		    is_array($config['laggs']['lagg'])) {
5768
			foreach ($config['laggs']['lagg'] as $lagg) {
5769
				if ($lagg['laggif'] == $interface) {
5770
					interface_lagg_configure($lagg);
5771
					break;
5772
				}
5773
			}
5774
		}
5775
	} else {
5776
		pfSense_interface_mtu($interface, $mtu);
5777
	}
5778
}
5779

    
5780
/****f* interfaces/get_interface_mtu
5781
 * NAME
5782
 *   get_interface_mtu - Return the mtu of an interface
5783
 * RESULT
5784
 *   $tmp       - Returns the mtu of an interface
5785
 ******/
5786
function get_interface_mtu($interface) {
5787
	$mtu = pfSense_interface_getmtu($interface);
5788
	return $mtu['mtu'];
5789
}
5790

    
5791
function get_interface_mac($interface) {
5792

    
5793
	$macinfo = pfSense_get_interface_addresses($interface);
5794
	return $macinfo["macaddr"];
5795
}
5796

    
5797
/****f* pfsense-utils/generate_random_mac_address
5798
 * NAME
5799
 *   generate_random_mac - generates a random mac address
5800
 * INPUTS
5801
 *   none
5802
 * RESULT
5803
 *   $mac - a random mac address
5804
 ******/
5805
function generate_random_mac_address() {
5806
	$mac = "02";
5807
	for ($x = 0; $x < 5; $x++) {
5808
		$mac .= ":" . dechex(rand(16, 255));
5809
	}
5810
	return $mac;
5811
}
5812

    
5813
/****f* interfaces/is_jumbo_capable
5814
 * NAME
5815
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5816
 * INPUTS
5817
 *   $int             - string containing interface name
5818
 * RESULT
5819
 *   boolean          - true or false
5820
 ******/
5821
function is_jumbo_capable($iface) {
5822
	$iface = trim($iface);
5823
	$capable = pfSense_get_interface_addresses($iface);
5824

    
5825
	if (isset($capable['caps']['vlanmtu'])) {
5826
		return true;
5827
	}
5828

    
5829
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5830
	if (substr($iface, 0, 4) == "lagg") {
5831
		return true;
5832
	}
5833

    
5834
	return false;
5835
}
5836

    
5837
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5838
	global $g;
5839

    
5840
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5841

    
5842
	if (!empty($iface) && !empty($pppif)) {
5843
		$cron_cmd = <<<EOD
5844
#!/bin/sh
5845
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5846
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5847

    
5848
EOD;
5849

    
5850
		@file_put_contents($cron_file, $cron_cmd);
5851
		chmod($cron_file, 0755);
5852
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5853
	} else {
5854
		unlink_if_exists($cron_file);
5855
	}
5856
}
5857

    
5858
function get_interface_default_mtu($type = "ethernet") {
5859
	switch ($type) {
5860
		case "gre":
5861
			return 1476;
5862
			break;
5863
		case "gif":
5864
			return 1280;
5865
			break;
5866
		case "tun":
5867
		case "vlan":
5868
		case "tap":
5869
		case "ethernet":
5870
		default:
5871
			return 1500;
5872
			break;
5873
	}
5874

    
5875
	/* Never reached */
5876
	return 1500;
5877
}
5878

    
5879
function get_vip_descr($ipaddress) {
5880
	global $config;
5881

    
5882
	foreach ($config['virtualip']['vip'] as $vip) {
5883
		if ($vip['subnet'] == $ipaddress) {
5884
			return ($vip['descr']);
5885
		}
5886
	}
5887
	return "";
5888
}
5889

    
5890
function interfaces_staticarp_configure($if) {
5891
	global $config, $g;
5892
	if (isset($config['system']['developerspew'])) {
5893
		$mt = microtime();
5894
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5895
	}
5896

    
5897
	$ifcfg = $config['interfaces'][$if];
5898

    
5899
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5900
		return 0;
5901
	}
5902

    
5903
	/* Enable staticarp, if enabled */
5904
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5905
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5906
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5907
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5908
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5909
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5910
			}
5911
		}
5912
	} else {
5913
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5914
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5915
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5916
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5917
				if (isset($arpent['arp_table_static_entry'])) {
5918
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5919
				}
5920
			}
5921
		}
5922
	}
5923

    
5924
	return 0;
5925
}
5926

    
5927
function get_failover_interface($interface, $family = "all") {
5928
	global $config;
5929

    
5930
	/* shortcut to get_real_interface if we find it in the config */
5931
	if (is_array($config['interfaces'][$interface])) {
5932
		return get_real_interface($interface, $family);
5933
	}
5934

    
5935
	/* compare against gateway groups */
5936
	$a_groups = return_gateway_groups_array();
5937
	if (is_array($a_groups[$interface])) {
5938
		/* we found a gateway group, fetch the interface or vip */
5939
		if (!empty($a_groups[$interface][0]['vip'])) {
5940
			return $a_groups[$interface][0]['vip'];
5941
		} else {
5942
			return $a_groups[$interface][0]['int'];
5943
		}
5944
	}
5945
	/* fall through to get_real_interface */
5946
	/* XXX: Really needed? */
5947
	return get_real_interface($interface, $family);
5948
}
5949

    
5950
function remove_ifindex($ifname) {
5951
	return preg_replace("/[0-9]+$/", "", $ifname);
5952
}
5953

    
5954
?>
(18-18/51)