Project

General

Profile

Download (174 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 (!empty($config['system']['global-v6duid'])) {
3872
		// Write the DUID file
3873
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
3874
		    log_error(gettext("Failed to write user DUID file!"));
3875
		}
3876
	}
3877
	
3878
	if ($wancfg['adv_dhcp6_config_file_override']) {
3879
		// DHCP6 Config File Override
3880
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3881
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3882
		// DHCP6 Config File Advanced
3883
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3884
	} else {
3885
		// DHCP6 Config File Basic
3886
		$dhcp6cconf .= "interface {$wanif} {\n";
3887

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

    
3904
			/* skip address request if this is set */
3905
			if (!isset($wancfg['dhcp6prefixonly'])) {
3906
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3907
			}
3908
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3909
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3910
			}
3911

    
3912
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3913
			$dhcp6cconf .= "\trequest domain-name;\n";
3914
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3915
			$dhcp6cconf .= "};\n";
3916

    
3917
			if (!isset($wancfg['dhcp6prefixonly'])) {
3918
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3919
			}
3920

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

    
3945
	/* wide-dhcp6c works for now. */
3946
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3947
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3948
		unset($dhcp6cconf);
3949
		return 1;
3950
	}
3951
	unset($dhcp6cconf);
3952

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

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

    
3973
	/* non ipoe Process */
3974
	if (!isset($wancfg['dhcp6withoutra'])) {
3975
		$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3976
		$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3977
		$rtsoldscript .= "\t/bin/sleep 1\n";
3978
		$rtsoldscript .= "fi\n";
3979
	} else {
3980
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
3981
		$rtsoldscript .= "/bin/sleep 1\n";
3982
	}
3983
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3984
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3985

    
3986

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

    
4001
	/* accept router advertisements for this interface */
4002
	log_error("Accept router advertisements on interface {$wanif} ");
4003
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4004

    
4005
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4006
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4007
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4008
		sleep(2);
4009
	}
4010

    
4011
	/* start dhcp6c here if we don't want to wait for ra */
4012
	if (isset($wancfg['dhcp6withoutra'])) {
4013
		kill_dhcp6client_process($wanif);
4014

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

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

    
4024
	return 0;
4025
}
4026

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4148
	$key_info_statement = "";
4149
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4150
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4151
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4152
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4153
		$key_info_statement .= "keyinfo";
4154
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4155
		$key_info_statement .= " {\n";
4156
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4157
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4158
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4159
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
4160
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4161
		}
4162
		$key_info_statement .= "};\n";
4163
	}
4164

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

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

    
4173
	return $dhcp6cconf;
4174
}
4175

    
4176

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

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

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

    
4189

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

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

    
4194
	return $dhcp6cconf;
4195
}
4196

    
4197

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

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

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

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

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

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

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

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

    
4246
}
4247

    
4248
EOD;
4249

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

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

    
4264
EOD;
4265
	}
4266

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

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

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

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

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

    
4288
	return 0;
4289
}
4290

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

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

    
4298
	/* DHCP Protocol Timings */
4299
	$protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
4300
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4301
		$pt_variable = "{$Protocol_Timing}";
4302
		${$pt_variable} = "";
4303
		if ($wancfg[$Protocol_Timing] != "") {
4304
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4305
		}
4306
	}
4307

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

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

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

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

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

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

    
4359
	return $dhclientconf;
4360
}
4361

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

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

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

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

    
4379

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

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

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

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

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

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

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

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

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

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

    
4432
	return $dhclientconf;
4433
}
4434

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

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

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

    
4446
	return;
4447
}
4448

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

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

    
4463
	return;
4464
}
4465

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

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

    
4477
	return false;
4478
}
4479

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4597
	return $ifdesc;
4598
}
4599

    
4600
function convert_real_interface_to_friendly_descr($interface) {
4601

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

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

    
4608
	return $interface;
4609
}
4610

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

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

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

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

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

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

    
4692
	return $parents;
4693
}
4694

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

    
4703
	$realif = get_parent_interface($interface);
4704

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

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

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

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

    
4740
function interface_list_wireless() {
4741
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
4742

    
4743
	$result = array();
4744
	foreach ($portlist as $port) {
4745
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
4746
			continue;
4747
		}
4748

    
4749
		$desc = $port . " ( " . get_single_sysctl(
4750
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
4751

    
4752
		$result[] = array(
4753
		    "if" => $port,
4754
		    "descr" => $desc
4755
		);
4756
	}
4757

    
4758
	return $result;
4759
}
4760

    
4761
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4762
	global $config, $g;
4763

    
4764
	$wanif = NULL;
4765

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

    
4808
			if (empty($config['interfaces'][$interface])) {
4809
				break;
4810
			}
4811

    
4812
			$cfg = &$config['interfaces'][$interface];
4813

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

    
4870
	return $wanif;
4871
}
4872

    
4873
/* Guess the physical interface by providing a IP address */
4874
function guess_interface_from_ip($ipaddress) {
4875

    
4876
	$family = '';
4877
	if (is_ipaddrv4($ipaddress)) {
4878
		$family = 'inet';
4879
	}
4880
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4881
		$family = 'inet6';
4882
	}
4883

    
4884
	if (empty($family)) {
4885
		return false;
4886
	}
4887

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

    
4896
	return false;
4897
}
4898

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

    
4908
	$isv6ip = is_ipaddrv6($ip);
4909

    
4910
	/* if list */
4911
	$ifdescrs = get_configured_interface_list();
4912

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

    
4931
	return false;
4932
}
4933

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

    
4941
	if (!is_array($config['virtualip']['vip'])) {
4942
		return false;
4943
	}
4944
	if (!is_ipaddr($ip)) {
4945
		return false;
4946
	}
4947

    
4948
	$isv6ip = is_ipaddrv6($ip);
4949

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

    
4970
function link_interface_to_track6($int, $action = "") {
4971
	global $config;
4972

    
4973
	if (empty($int)) {
4974
		return;
4975
	}
4976

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

    
4995
function interface_find_child_cfgmtu($realiface) {
4996
	global $config;
4997

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

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

    
5071
	return $mtu;
5072
}
5073

    
5074
function link_interface_to_vlans($int, $action = "") {
5075
	global $config;
5076

    
5077
	if (empty($int)) {
5078
		return;
5079
	}
5080

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

    
5098
function link_interface_to_qinqs($int, $action = "") {
5099
	global $config;
5100

    
5101
	if (empty($int)) {
5102
		return;
5103
	}
5104

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

    
5122
function link_interface_to_vips($int, $action = "", $vhid = '') {
5123
	global $config;
5124

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

    
5152
	return NULL;
5153
}
5154

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

    
5166
	if (is_array($config['bridges']['bridged'])) {
5167
		foreach ($config['bridges']['bridged'] as $bridge) {
5168
			if (in_array($int, explode(',', $bridge['members']))) {
5169
				return "{$bridge['bridgeif']}";
5170
			}
5171
		}
5172
	}
5173
}
5174

    
5175
function link_interface_to_group($int) {
5176
	global $config;
5177

    
5178
	$result = array();
5179

    
5180
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5181
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5182
			if (in_array($int, explode(" ", $group['members']))) {
5183
				$result[$group['ifname']] = $int;
5184
			}
5185
		}
5186
	}
5187

    
5188
	return $result;
5189
}
5190

    
5191
function link_interface_to_gre($interface) {
5192
	global $config;
5193

    
5194
	$result = array();
5195

    
5196
	if (is_array($config['gres']['gre'])) {
5197
		foreach ($config['gres']['gre'] as $gre) {
5198
			if ($gre['if'] == $interface) {
5199
				$result[] = $gre;
5200
			}
5201
		}
5202
	}
5203

    
5204
	return $result;
5205
}
5206

    
5207
function link_interface_to_gif($interface) {
5208
	global $config;
5209

    
5210
	$result = array();
5211

    
5212
	if (is_array($config['gifs']['gif'])) {
5213
		foreach ($config['gifs']['gif'] as $gif) {
5214
			if ($gif['if'] == $interface) {
5215
				$result[] = $gif;
5216
			}
5217
		}
5218
	}
5219

    
5220
	return $result;
5221
}
5222

    
5223
/*
5224
 * find_interface_ip($interface): return the interface ip (first found)
5225
 */
5226
function find_interface_ip($interface, $flush = false) {
5227
	global $interface_ip_arr_cache;
5228
	global $interface_sn_arr_cache;
5229

    
5230
	$interface = str_replace("\n", "", $interface);
5231

    
5232
	if (!does_interface_exist($interface)) {
5233
		return;
5234
	}
5235

    
5236
	/* Setup IP cache */
5237
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5238
		if (file_exists("/var/db/${interface}_ip")) {
5239
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5240
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5241
			foreach ($ifaddrs as $ifaddr) {
5242
				list($ip, $mask) = explode("/", $ifaddr);
5243
				if ($ip == $ifip) {
5244
					$interface_ip_arr_cache[$interface] = $ip;
5245
					$interface_sn_arr_cache[$interface] = $mask;
5246
					break;
5247
				}
5248
			}
5249
		}
5250
		if (!isset($interface_ip_arr_cache[$interface])) {
5251
			$ifinfo = pfSense_get_interface_addresses($interface);
5252
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5253
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5254
		}
5255
	}
5256

    
5257
	return $interface_ip_arr_cache[$interface];
5258
}
5259

    
5260
/*
5261
 * find_interface_ipv6($interface): return the interface ip (first found)
5262
 */
5263
function find_interface_ipv6($interface, $flush = false) {
5264
	global $interface_ipv6_arr_cache;
5265
	global $interface_snv6_arr_cache;
5266
	global $config;
5267

    
5268
	$interface = trim($interface);
5269
	$interface = get_real_interface($interface);
5270

    
5271
	if (!does_interface_exist($interface)) {
5272
		return;
5273
	}
5274

    
5275
	/* Setup IP cache */
5276
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5277
		$ifinfo = pfSense_get_interface_addresses($interface);
5278
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5279
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5280
	}
5281

    
5282
	return $interface_ipv6_arr_cache[$interface];
5283
}
5284

    
5285
/*
5286
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5287
 */
5288
function find_interface_ipv6_ll($interface, $flush = false) {
5289
	global $interface_llv6_arr_cache;
5290
	global $config;
5291

    
5292
	$interface = str_replace("\n", "", $interface);
5293

    
5294
	if (!does_interface_exist($interface)) {
5295
		return;
5296
	}
5297

    
5298
	/* Setup IP cache */
5299
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5300
		$ifinfo = pfSense_getall_interface_addresses($interface);
5301
		foreach ($ifinfo as $line) {
5302
			if (strstr($line, ":")) {
5303
				$parts = explode("/", $line);
5304
				if (is_linklocal($parts[0])) {
5305
					$ifinfo['linklocal'] = $parts[0];
5306
				}
5307
			}
5308
		}
5309
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5310
	}
5311
	return $interface_llv6_arr_cache[$interface];
5312
}
5313

    
5314
function find_interface_subnet($interface, $flush = false) {
5315
	global $interface_sn_arr_cache;
5316
	global $interface_ip_arr_cache;
5317

    
5318
	$interface = str_replace("\n", "", $interface);
5319
	if (does_interface_exist($interface) == false) {
5320
		return;
5321
	}
5322

    
5323
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5324
		$ifinfo = pfSense_get_interface_addresses($interface);
5325
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5326
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5327
	}
5328

    
5329
	return $interface_sn_arr_cache[$interface];
5330
}
5331

    
5332
function find_interface_subnetv6($interface, $flush = false) {
5333
	global $interface_snv6_arr_cache;
5334
	global $interface_ipv6_arr_cache;
5335

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

    
5341
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5342
		$ifinfo = pfSense_get_interface_addresses($interface);
5343
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5344
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5345
	}
5346

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

    
5350
function ip_in_interface_alias_subnet($interface, $ipalias) {
5351
	global $config;
5352

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

    
5372
	return false;
5373
}
5374

    
5375
function get_possible_listen_ips($include_ipv6_link_local=false) {
5376

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

    
5398
	$interfaces['lo0'] = 'Localhost';
5399

    
5400
	return $interfaces;
5401
}
5402

    
5403
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5404
	global $config;
5405

    
5406
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5407
	foreach (array('server', 'client') as $mode) {
5408
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5409
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5410
				if (!isset($setting['disable'])) {
5411
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5412
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5413
				}
5414
			}
5415
		}
5416
	}
5417
	return $sourceips;
5418
}
5419

    
5420
function get_interface_ip($interface = "wan") {
5421

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

    
5429
	$realif = get_failover_interface($interface, 'inet');
5430
	if (!$realif) {
5431
		return null;
5432
	}
5433

    
5434
	if (substr($realif, 0, 4) == '_vip') {
5435
		return get_configured_vip_ipv4($realif);
5436
	} else if (substr($realif, 0, 5) == '_lloc') {
5437
		/* No link-local address for v4. */
5438
		return null;
5439
	}
5440

    
5441
	if (is_array($config['interfaces'][$interface]) &&
5442
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5443
		return ($config['interfaces'][$interface]['ipaddr']);
5444
	}
5445

    
5446
	/*
5447
	 * Beaware that find_interface_ip() is our last option, it will
5448
	 * return the first IP it find on interface, not necessarily the
5449
	 * main IP address.
5450
	 */
5451
	$curip = find_interface_ip($realif);
5452
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5453
		return $curip;
5454
	} else {
5455
		return null;
5456
	}
5457
}
5458

    
5459
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5460
	global $config;
5461

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

    
5468
	$realif = get_failover_interface($interface, 'inet6');
5469
	if (!$realif) {
5470
		return null;
5471
	}
5472

    
5473
	if (substr($realif, 0, 4) == '_vip') {
5474
		return get_configured_vip_ipv6($realif);
5475
	} else if (substr($realif, 0, 5) == '_lloc') {
5476
		return get_interface_linklocal($realif);
5477
	}
5478

    
5479
	if (is_array($config['interfaces'][$interface])) {
5480
		switch ($config['interfaces'][$interface]['ipaddr']) {
5481
			case 'pppoe':
5482
			case 'l2tp':
5483
			case 'pptp':
5484
			case 'ppp':
5485
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5486
					$realif = get_real_interface($interface, 'inet6', false);
5487
				}
5488
				break;
5489
		}
5490
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5491
			return ($config['interfaces'][$interface]['ipaddrv6']);
5492
		}
5493
	}
5494

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

    
5518
function get_interface_linklocal($interface = "wan") {
5519

    
5520
	$realif = get_failover_interface($interface, 'inet6');
5521
	if (!$realif) {
5522
		return null;
5523
	}
5524

    
5525
	if (substr($interface, 0, 4) == '_vip') {
5526
		$realif = get_real_interface($interface);
5527
	} else if (substr($interface, 0, 5) == '_lloc') {
5528
		$realif = get_real_interface(substr($interface, 5));
5529
	}
5530

    
5531
	$curip = find_interface_ipv6_ll($realif);
5532
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5533
		return $curip;
5534
	} else {
5535
		return null;
5536
	}
5537
}
5538

    
5539
function get_interface_subnet($interface = "wan") {
5540

    
5541
	if (substr($interface, 0, 4) == '_vip') {
5542
		return (get_configured_vip_subnetv4($interface));
5543
	}
5544

    
5545
	$realif = get_real_interface($interface);
5546
	if (!$realif) {
5547
		return (NULL);
5548
	}
5549

    
5550
	$cursn = find_interface_subnet($realif);
5551
	if (!empty($cursn)) {
5552
		return ($cursn);
5553
	}
5554

    
5555
	return (NULL);
5556
}
5557

    
5558
function get_interface_subnetv6($interface = "wan") {
5559

    
5560
	if (substr($interface, 0, 4) == '_vip') {
5561
		return (get_configured_vip_subnetv6($interface));
5562
	} else if (substr($interface, 0, 5) == '_lloc') {
5563
		$interface = substr($interface, 5);
5564
	}
5565

    
5566
	$realif = get_real_interface($interface, 'inet6');
5567
	if (!$realif) {
5568
		return (NULL);
5569
	}
5570

    
5571
	$cursn = find_interface_subnetv6($realif);
5572
	if (!empty($cursn)) {
5573
		return ($cursn);
5574
	}
5575

    
5576
	return (NULL);
5577
}
5578

    
5579
/* return outside interfaces with a gateway */
5580
function get_interfaces_with_gateway() {
5581
	global $config;
5582

    
5583
	$ints = array();
5584

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

    
5606
/* return true if interface has a gateway */
5607
function interface_has_gateway($friendly) {
5608
	global $config;
5609

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

    
5637
	return false;
5638
}
5639

    
5640
/* return true if interface has a gateway */
5641
function interface_has_gatewayv6($friendly) {
5642
	global $config;
5643

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

    
5670
	return false;
5671
}
5672

    
5673
/****f* interfaces/is_altq_capable
5674
 * NAME
5675
 *   is_altq_capable - Test if interface is capable of using ALTQ
5676
 * INPUTS
5677
 *   $int            - string containing interface name
5678
 * RESULT
5679
 *   boolean         - true or false
5680
 ******/
5681

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

    
5696
	$int_family = remove_ifindex($int);
5697

    
5698
	if (in_array($int_family, $capable)) {
5699
		return true;
5700
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5701
		return true;
5702
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5703
		return true;
5704
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5705
		return true;
5706
	} else {
5707
		return false;
5708
	}
5709
}
5710

    
5711
/****f* interfaces/is_interface_wireless
5712
 * NAME
5713
 *   is_interface_wireless - Returns if an interface is wireless
5714
 * RESULT
5715
 *   $tmp       - Returns if an interface is wireless
5716
 ******/
5717
function is_interface_wireless($interface) {
5718
	global $config, $g;
5719

    
5720
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5721
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5722
		if (preg_match($g['wireless_regex'], $interface)) {
5723
			if (isset($config['interfaces'][$friendly])) {
5724
				$config['interfaces'][$friendly]['wireless'] = array();
5725
			}
5726
			return true;
5727
		}
5728
		return false;
5729
	} else {
5730
		return true;
5731
	}
5732
}
5733

    
5734
function get_wireless_modes($interface) {
5735
	/* return wireless modes and channels */
5736
	$wireless_modes = array();
5737

    
5738
	$cloned_interface = get_real_interface($interface);
5739

    
5740
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5741
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5742
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5743
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5744

    
5745
		$interface_channels = "";
5746
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5747
		$interface_channel_count = count($interface_channels);
5748

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

    
5782
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5783
function get_wireless_channel_info($interface) {
5784
	$wireless_channels = array();
5785

    
5786
	$cloned_interface = get_real_interface($interface);
5787

    
5788
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5789
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5790
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5791
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5792

    
5793
		$interface_channels = "";
5794
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5795

    
5796
		foreach ($interface_channels as $channel_line) {
5797
			$channel_line = explode(",", $channel_line);
5798
			if (!isset($wireless_channels[$channel_line[0]])) {
5799
				$wireless_channels[$channel_line[0]] = $channel_line;
5800
			}
5801
		}
5802
	}
5803
	return($wireless_channels);
5804
}
5805

    
5806
function set_interface_mtu($interface, $mtu) {
5807

    
5808
	/* LAGG interface must be destroyed and re-created to change MTU */
5809
	if (substr($interface, 0, 4) == 'lagg') {
5810
		if (isset($config['laggs']['lagg']) &&
5811
		    is_array($config['laggs']['lagg'])) {
5812
			foreach ($config['laggs']['lagg'] as $lagg) {
5813
				if ($lagg['laggif'] == $interface) {
5814
					interface_lagg_configure($lagg);
5815
					break;
5816
				}
5817
			}
5818
		}
5819
	} else {
5820
		pfSense_interface_mtu($interface, $mtu);
5821
	}
5822
}
5823

    
5824
/****f* interfaces/get_interface_mtu
5825
 * NAME
5826
 *   get_interface_mtu - Return the mtu of an interface
5827
 * RESULT
5828
 *   $tmp       - Returns the mtu of an interface
5829
 ******/
5830
function get_interface_mtu($interface) {
5831
	$mtu = pfSense_interface_getmtu($interface);
5832
	return $mtu['mtu'];
5833
}
5834

    
5835
function get_interface_mac($interface) {
5836

    
5837
	$macinfo = pfSense_get_interface_addresses($interface);
5838
	return $macinfo["macaddr"];
5839
}
5840

    
5841
/****f* pfsense-utils/generate_random_mac_address
5842
 * NAME
5843
 *   generate_random_mac - generates a random mac address
5844
 * INPUTS
5845
 *   none
5846
 * RESULT
5847
 *   $mac - a random mac address
5848
 ******/
5849
function generate_random_mac_address() {
5850
	$mac = "02";
5851
	for ($x = 0; $x < 5; $x++) {
5852
		$mac .= ":" . dechex(rand(16, 255));
5853
	}
5854
	return $mac;
5855
}
5856

    
5857
/****f* interfaces/is_jumbo_capable
5858
 * NAME
5859
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5860
 * INPUTS
5861
 *   $int             - string containing interface name
5862
 * RESULT
5863
 *   boolean          - true or false
5864
 ******/
5865
function is_jumbo_capable($iface) {
5866
	$iface = trim($iface);
5867
	$capable = pfSense_get_interface_addresses($iface);
5868

    
5869
	if (isset($capable['caps']['vlanmtu'])) {
5870
		return true;
5871
	}
5872

    
5873
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5874
	if (substr($iface, 0, 4) == "lagg") {
5875
		return true;
5876
	}
5877

    
5878
	return false;
5879
}
5880

    
5881
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5882
	global $g;
5883

    
5884
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5885

    
5886
	if (!empty($iface) && !empty($pppif)) {
5887
		$cron_cmd = <<<EOD
5888
#!/bin/sh
5889
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5890
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5891

    
5892
EOD;
5893

    
5894
		@file_put_contents($cron_file, $cron_cmd);
5895
		chmod($cron_file, 0755);
5896
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5897
	} else {
5898
		unlink_if_exists($cron_file);
5899
	}
5900
}
5901

    
5902
function get_interface_default_mtu($type = "ethernet") {
5903
	switch ($type) {
5904
		case "gre":
5905
			return 1476;
5906
			break;
5907
		case "gif":
5908
			return 1280;
5909
			break;
5910
		case "tun":
5911
		case "vlan":
5912
		case "tap":
5913
		case "ethernet":
5914
		default:
5915
			return 1500;
5916
			break;
5917
	}
5918

    
5919
	/* Never reached */
5920
	return 1500;
5921
}
5922

    
5923
function get_vip_descr($ipaddress) {
5924
	global $config;
5925

    
5926
	foreach ($config['virtualip']['vip'] as $vip) {
5927
		if ($vip['subnet'] == $ipaddress) {
5928
			return ($vip['descr']);
5929
		}
5930
	}
5931
	return "";
5932
}
5933

    
5934
function interfaces_staticarp_configure($if) {
5935
	global $config, $g;
5936
	if (isset($config['system']['developerspew'])) {
5937
		$mt = microtime();
5938
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5939
	}
5940

    
5941
	$ifcfg = $config['interfaces'][$if];
5942

    
5943
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5944
		return 0;
5945
	}
5946

    
5947
	/* Enable staticarp, if enabled */
5948
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5949
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5950
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5951
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5952
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5953
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
5954
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5955
				}
5956
			}
5957
		}
5958
	} else {
5959
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5960
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5961
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5962
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5963
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
5964
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5965
				}
5966
			}
5967
		}
5968
	}
5969

    
5970
	return 0;
5971
}
5972

    
5973
function get_failover_interface($interface, $family = "all") {
5974
	global $config;
5975

    
5976
	/* shortcut to get_real_interface if we find it in the config */
5977
	if (is_array($config['interfaces'][$interface])) {
5978
		return get_real_interface($interface, $family);
5979
	}
5980

    
5981
	/* compare against gateway groups */
5982
	$a_groups = return_gateway_groups_array();
5983
	if (is_array($a_groups[$interface])) {
5984
		/* we found a gateway group, fetch the interface or vip */
5985
		if (!empty($a_groups[$interface][0]['vip'])) {
5986
			return $a_groups[$interface][0]['vip'];
5987
		} else {
5988
			return $a_groups[$interface][0]['int'];
5989
		}
5990
	}
5991
	/* fall through to get_real_interface */
5992
	/* XXX: Really needed? */
5993
	return get_real_interface($interface, $family);
5994
}
5995

    
5996
/****f* interfaces/interface_has_dhcp
5997
 * NAME
5998
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
5999
 * INPUTS
6000
 *   interface or gateway group name
6001
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6002
 * RESULT
6003
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6004
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6005
 ******/
6006
function interface_has_dhcp($interface, $family = 4) {
6007
	global $config;
6008

    
6009
	if ($config['interfaces'][$interface]) {
6010
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6011
			return true;
6012
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6013
			return true;
6014
		} else {
6015
			return false;
6016
		}
6017
	}
6018

    
6019
	if (!is_array($config['gateways']['gateway_group'])) {
6020
		return false;
6021
	}
6022

    
6023
	if ($family == 6) {
6024
		$dhcp_string = "_DHCP6";
6025
	} else {
6026
		$dhcp_string = "_DHCP";
6027
	}
6028

    
6029
	foreach ($config['gateways']['gateway_group'] as $group) {
6030
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6031
			continue;
6032
		}
6033
		foreach ($group['item'] as $item) {
6034
			$item_data = explode("|", $item);
6035
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6036
				return true;
6037
			}
6038
		}
6039
	}
6040

    
6041
	return false;
6042
}
6043

    
6044
function remove_ifindex($ifname) {
6045
	return preg_replace("/[0-9]+$/", "", $ifname);
6046
}
6047

    
6048
?>
(18-18/51)