Project

General

Profile

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

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

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

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

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

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

    
1396
	return;
1397
}
1398

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

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

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

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

    
1432
	return false;
1433
}
1434

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

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

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

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

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

    
1466
	return false;
1467
}
1468

    
1469
function interfaces_ptpid_next() {
1470

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

    
1476
	return $ptpid;
1477
}
1478

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

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

    
1491
	return NULL;
1492
}
1493

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

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

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

    
1504
	$itemhash = getMPDCRONSettings($pppif);
1505

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

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

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

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

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

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

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

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

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

    
1667
				if (!is_ipaddr($localips[$pid])) {
1668
					log_error(sprintf(gettext("Could not get a Local IP address for PPTP/L2TP link on %s in interfaces_ppps_configure. Using 0.0.0.0 ip!"), $port));
1669
					$localips[$pid] = "0.0.0.0";
1670
				}
1671
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1672
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1673
				}
1674
				if (!is_ipaddr($gateways[$pid])) {
1675
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
1676
					return 0;
1677
				}
1678
				pfSense_ngctl_attach(".", $port);
1679
				break;
1680
			case "ppp":
1681
				if (!file_exists("{$port}")) {
1682
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1683
					return 0;
1684
				}
1685
				break;
1686
			default:
1687
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1688
				break;
1689
		}
1690
	}
1691

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

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

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

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

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

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

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

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

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

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

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

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

    
1798
EOD;
1799

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

    
1804
EOD;
1805
	}
1806

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

    
1815
EOD;
1816

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

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

    
1827
EOD;
1828
	}
1829

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

    
1835
EOD;
1836
	}
1837

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

    
1842
EOD;
1843
	}
1844

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

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

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

    
1860
EOD;
1861
		}
1862

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

    
1867
EOD;
1868
		}
1869

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

    
1874
EOD;
1875
		}
1876

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

    
1882
EOD;
1883

    
1884

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

    
1889
EOD;
1890
		}
1891

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

    
1905
EOD;
1906
		}
1907

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

    
1912
EOD;
1913
		}
1914

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

    
1919
EOD;
1920
		}
1921

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

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

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

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

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

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

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

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

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

    
1986
EOD;
1987
		}
1988

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

    
1994
EOD;
1995
		}
1996

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

    
2000

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

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

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

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

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

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

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

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

    
2107
	return 1;
2108
}
2109

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

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

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

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

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

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

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

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

    
2155
		sleep(1);
2156

    
2157
		/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
2158
		 * for existing sessions.
2159
		 */
2160
		log_error(gettext("waiting for pfsync..."));
2161
		$i = 0;
2162
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2163
			$i++;
2164
			sleep(1);
2165
		}
2166
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2167
		log_error(gettext("Configuring CARP settings finalize..."));
2168
	} else {
2169
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2170
	}
2171

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2420
	return $realif;
2421
}
2422

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2778
EOD;
2779

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

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

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

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

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

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

    
2814
EOD;
2815
						}
2816
					}
2817
				}
2818

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

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

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

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

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

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

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

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

    
2875
	fclose($fd_set);
2876

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2981
	unset($wlcmd_args, $wlcmd);
2982

    
2983

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

    
2988
	return 0;
2989

    
2990
}
2991

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

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

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

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

    
3011
	return intval($pid);
3012
}
3013

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

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

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

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

    
3039
	return intval($pid);
3040
}
3041

    
3042
function kill_dhcp6client_process($interface, $norelease) {
3043
	global $g;
3044

    
3045
	if (empty($interface) || !does_interface_exist($interface)) {
3046
		return;
3047
	}
3048

    
3049
	if (($pid = find_dhcp6c_process($interface)) != 0) {
3050
		/*
3051
		 * Kill -9 caused the pid to get left behind, also if we need a
3052
		 * relase sent then it needs to be -15, this then allows dhcp6c
3053
		 * to send the release, it will also clean up after itself
3054
		 */
3055
		$sig = (isset($norelease) ? SIGKILL : SIGTERM);
3056
		posix_kill($pid, $sig);
3057
		if(!isset($norelease)) {
3058
			/*
3059
			 * Allow dhcp6c to send release and exit gracefully if
3060
			 * needed.
3061
			 */
3062
			sleep(2);
3063
		}
3064
	}
3065
	/* Clear the RTSOLD script created lock  & tidy up */
3066
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3067
	/* just in case! */
3068
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid");
3069
}
3070

    
3071
function run_dhcp6client_process($interface, $wancfg) {
3072
	global $g;
3073

    
3074
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3075
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3076

    
3077
	/*
3078
	 * Only run this if the lock does not exist. In theory the lock being
3079
	 * there in this mode means the user has selected dhcp6withoutRA while
3080
	 * a session is active in the other mode.
3081
	 *
3082
	 * It should not happen as the process should have been killed and the
3083
	 * lock deleted.
3084
	 */
3085
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3086
		kill_dhcp6client_process($interface,
3087
		    isset($wancfg['dhcp6norelease']));
3088

    
3089
		/* Lock it to avoid multiple runs */
3090
		touch("/tmp/dhcp6c_{$interface}_lock");
3091
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3092
		    "{$noreleaseOption} " .
3093
		    "-c {$g['varetc_path']}/dhcp6c_wan.conf " .
3094
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3095
		    $interface);
3096
		log_error(sprintf(gettext(
3097
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3098
		    $wanif));
3099
	}
3100
}
3101

    
3102
function interface_virtual_create($interface) {
3103
	global $config;
3104

    
3105
	if (strstr($interface, "_vlan")) {
3106
		interfaces_vlan_configure($vlan);
3107
	} else if (substr($interface, 0, 3) == "gre") {
3108
		interfaces_gre_configure(0, $interface);
3109
	} else if (substr($interface, 0, 3) == "gif") {
3110
		interfaces_gif_configure(0, $interface);
3111
	} else if (substr($interface, 0, 5) == "ovpns") {
3112
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3113
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3114
				if ($interface == "ovpns{$server['vpnid']}") {
3115
					if (!function_exists('openvpn_resync')) {
3116
						require_once('openvpn.inc');
3117
					}
3118
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3119
					openvpn_resync('server', $server);
3120
				}
3121
			}
3122
			unset($server);
3123
		}
3124
	} else if (substr($interface, 0, 5) == "ovpnc") {
3125
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3126
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3127
				if ($interface == "ovpnc{$client['vpnid']}") {
3128
					if (!function_exists('openvpn_resync')) {
3129
						require_once('openvpn.inc');
3130
					}
3131
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3132
					openvpn_resync('client', $client);
3133
				}
3134
			}
3135
			unset($client);
3136
		}
3137
	} else if (substr($interface, 0, 4) == "lagg") {
3138
		interfaces_lagg_configure($interface);
3139
	} else if (substr($interface, 0, 6) == "bridge") {
3140
		interfaces_bridge_configure(0, $interface);
3141
	}
3142
}
3143

    
3144
function interface_vlan_mtu_configured($iface) {
3145
	global $config;
3146

    
3147
	$mtu = 0;
3148
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3149
		foreach ($config['vlans']['vlan'] as $vlan) {
3150

    
3151
			if ($vlan['vlanif'] != $iface)
3152
				continue;
3153

    
3154
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3155
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3156
				/* VLAN MTU */
3157
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3158
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3159
				/* Parent MTU */
3160
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3161
			}
3162
		}
3163
	}
3164

    
3165
	return $mtu;
3166
}
3167

    
3168
function interface_mtu_wanted_for_pppoe($realif) {
3169
	global $config;
3170

    
3171
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3172
		return 0;
3173

    
3174
	$mtu = 0;
3175
	foreach ($config['ppps']['ppp'] as $ppp) {
3176
		if ($ppp['type'] != "pppoe") {
3177
			continue;
3178
		}
3179

    
3180
		$mtus = array();
3181
		if (!empty($ppp['mtu'])) {
3182
			$mtus = explode(',', $ppp['mtu']);
3183
		}
3184
		$ports = explode(',', $ppp['ports']);
3185

    
3186
		foreach ($ports as $pid => $port) {
3187
			$parentifa = get_parent_interface($port);
3188
			$parentif = $parentifa[0];
3189
			if ($parentif != $realif)
3190
				continue;
3191

    
3192
			// there is an MTU configured on the port in question
3193
			if (!empty($mtus[$pid])) {
3194
				$mtu = intval($mtus[$pid]) + 8;
3195
			// or use the MTU configured on the interface ...
3196
			} elseif (is_array($config['interfaces'])) {
3197
				foreach ($config['interfaces'] as $interface) {
3198
					if ($interface['if'] == $ppp['if'] &&
3199
					    !empty($interface['mtu'])) {
3200
						$mtu = intval($interface['mtu']) + 8;
3201
						break;
3202
					}
3203
				}
3204
			}
3205
		}
3206
	}
3207

    
3208
	return $mtu;
3209
}
3210

    
3211
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3212
	global $config, $g;
3213
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3214
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3215

    
3216
	$wancfg = $config['interfaces'][$interface];
3217

    
3218
	if (!isset($wancfg['enable'])) {
3219
		return;
3220
	}
3221

    
3222
	$realif = get_real_interface($interface);
3223
	$realhwif_array = get_parent_interface($interface);
3224
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3225
	$realhwif = $realhwif_array[0];
3226

    
3227
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3228
		/* remove all IPv4 and IPv6 addresses */
3229
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3230
		if (is_array($tmpifaces)) {
3231
			foreach ($tmpifaces as $tmpiface) {
3232
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3233
					if (!is_linklocal($tmpiface)) {
3234
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3235
					}
3236
				} else {
3237
					if (is_subnetv4($tmpiface)) {
3238
						$tmpip = explode('/', $tmpiface);
3239
						$tmpip = $tmpip[0];
3240
					} else {
3241
						$tmpip = $tmpiface;
3242
					}
3243
					pfSense_interface_deladdress($realif, $tmpip);
3244
				}
3245
			}
3246
		}
3247

    
3248
		/* only bring down the interface when both v4 and v6 are set to NONE */
3249
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3250
			interface_bring_down($interface);
3251
		}
3252
	}
3253

    
3254
	$interface_to_check = $realif;
3255
	if (interface_isppp_type($interface)) {
3256
		$interface_to_check = $realhwif;
3257
	}
3258

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

    
3264
	/* Disable Accepting router advertisements unless specifically requested */
3265
	if ($g['debug']) {
3266
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3267
	}
3268
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3269

    
3270
	/* wireless configuration? */
3271
	if (is_array($wancfg['wireless'])) {
3272
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3273
	}
3274

    
3275
	/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3276
	$current_mac = get_interface_mac($realhwif);
3277
	if (platform_booting()) {
3278
		$vendor_mac = $current_mac;
3279
	} else {
3280
		$vendor_mac = get_interface_vendor_mac($realhwif);
3281
	}
3282
	$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3283
	/*
3284
	 * Don't try to reapply the MAC if it's already applied.
3285
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3286
	 * the interface config again, which attempts to apply the MAC again,
3287
	 * which cycles the link again...
3288
	 */
3289
	if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3290
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3291
			" link " . escapeshellarg($mac_addr));
3292
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3293
		/*   this is not a valid mac address.  generate a
3294
		 *   temporary mac address so the machine can get online.
3295
		 */
3296
		echo gettext("Generating new MAC address.");
3297
		$random_mac = generate_random_mac_address();
3298
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3299
			" link " . escapeshellarg($random_mac));
3300
		$wancfg['spoofmac'] = $random_mac;
3301
		write_config();
3302
		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");
3303
	}
3304

    
3305
	/* media */
3306
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3307
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3308
		if ($wancfg['media']) {
3309
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3310
		}
3311
		if ($wancfg['mediaopt']) {
3312
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3313
		}
3314
		mwexec($cmd);
3315
	}
3316

    
3317
	/* Apply hw offloading policies as configured */
3318
	enable_hardware_offloading($interface);
3319

    
3320
	/* invalidate interface/ip/sn cache */
3321
	get_interface_arr(true);
3322
	unset($interface_ip_arr_cache[$realif]);
3323
	unset($interface_sn_arr_cache[$realif]);
3324
	unset($interface_ipv6_arr_cache[$realif]);
3325
	unset($interface_snv6_arr_cache[$realif]);
3326

    
3327
	$tunnelif = substr($realif, 0, 3);
3328

    
3329
	$mtuif = $realif;
3330
	$mtuhwif = $realhwif;
3331

    
3332
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3333
	if (interface_isppp_type($interface)) {
3334
		$mtuif = $realhwif;
3335
		$mtuhwif_array = get_parent_interface($mtuif);
3336
		$mtuhwif = $mtuhwif_array[0];
3337
	}
3338

    
3339
	$wantedmtu = 0;
3340
	if (is_array($config['interfaces'])) {
3341
		foreach ($config['interfaces'] as $tmpinterface) {
3342
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3343
				$wantedmtu = $tmpinterface['mtu'];
3344
				break;
3345
			}
3346
		}
3347
	}
3348

    
3349
	/* MTU is not specified for interface, try the pppoe settings. */
3350
	if ($wantedmtu == 0) {
3351
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3352
	}
3353
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3354
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3355
	}
3356

    
3357
	/* Set the MTU to 1500 if no explicit MTU configured. */
3358
	if ($wantedmtu == 0) {
3359
		$wantedmtu = 1500; /* Default */
3360
	}
3361

    
3362
	if (stristr($mtuif, "_vlan")) {
3363
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3364
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3365
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3366
			if ($wancfg['mtu'] > $parentmtu) {
3367
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3368
			}
3369
		}
3370

    
3371
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3372

    
3373
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3374
			$configuredmtu = $parentmtu;
3375
		if ($configuredmtu != 0)
3376
			$mtu = $configuredmtu;
3377
		else
3378
			$mtu = $wantedmtu;
3379

    
3380
		/* Set the parent MTU. */
3381
		if (get_interface_mtu($mtuhwif) < $mtu)
3382
			set_interface_mtu($mtuhwif, $mtu);
3383
		/* Set the VLAN MTU. */
3384
		if (get_interface_mtu($mtuif) != $mtu)
3385
			set_interface_mtu($mtuif, $mtu);
3386
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3387
		/* LAGG interface must be destroyed and re-created to change MTU */
3388
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3389
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3390
				foreach ($config['laggs']['lagg'] as $lagg) {
3391
					if ($lagg['laggif'] == $mtuif) {
3392
						interface_lagg_configure($lagg);
3393
						break;
3394
					}
3395
				}
3396
			}
3397
		}
3398
	} else {
3399
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3400
			pfSense_interface_mtu($mtuif, $wantedmtu);
3401
		}
3402
	}
3403
	/* XXX: What about gre/gif/.. ? */
3404

    
3405
	if (does_interface_exist($wancfg['if'])) {
3406
		interfaces_bring_up($wancfg['if']);
3407
	}
3408

    
3409
	switch ($wancfg['ipaddr']) {
3410
		case 'dhcp':
3411
			interface_dhcp_configure($interface);
3412
			break;
3413
		case 'pppoe':
3414
		case 'l2tp':
3415
		case 'pptp':
3416
		case 'ppp':
3417
			interface_ppps_configure($interface);
3418
			break;
3419
		default:
3420
			/* XXX: Kludge for now related to #3280 */
3421
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3422
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3423
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3424
				}
3425
			}
3426
			break;
3427
	}
3428

    
3429
	switch ($wancfg['ipaddrv6']) {
3430
		case 'slaac':
3431
		case 'dhcp6':
3432
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3433
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3434
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3435
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3436
				interface_dhcpv6_configure($interface, $wancfg);
3437
			}
3438
			break;
3439
		case '6rd':
3440
			interface_6rd_configure($interface, $wancfg);
3441
			break;
3442
		case '6to4':
3443
			interface_6to4_configure($interface, $wancfg);
3444
			break;
3445
		case 'track6':
3446
			interface_track6_configure($interface, $wancfg, $linkupevent);
3447
			break;
3448
		default:
3449
			/* XXX: Kludge for now related to #3280 */
3450
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3451
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3452
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3453
					// FIXME: Add IPv6 Support to the pfSense module
3454
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3455
				}
3456
			}
3457
			break;
3458
	}
3459

    
3460
	interface_netgraph_needed($interface);
3461

    
3462
	if (!platform_booting()) {
3463
		link_interface_to_vips($interface, "update");
3464

    
3465
		if ($tunnelif != 'gre') {
3466
			unset($gre);
3467
			$gre = link_interface_to_gre($interface);
3468
			if (!empty($gre)) {
3469
				array_walk($gre, 'interface_gre_configure');
3470
			}
3471
		}
3472

    
3473
		if ($tunnelif != 'gif') {
3474
			unset($gif);
3475
			$gif = link_interface_to_gif ($interface);
3476
			if (!empty($gif)) {
3477
				array_walk($gif, 'interface_gif_configure');
3478
			}
3479
		}
3480

    
3481
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3482
			unset($bridgetmp);
3483
			$bridgetmp = link_interface_to_bridge($interface);
3484
			if (!empty($bridgetmp)) {
3485
				interface_bridge_add_member($bridgetmp, $realif);
3486
			}
3487
		}
3488

    
3489
		$grouptmp = link_interface_to_group($interface);
3490
		if (!empty($grouptmp)) {
3491
			array_walk($grouptmp, 'interface_group_add_member');
3492
		}
3493

    
3494
		if ($interface == "lan") {
3495
			/* make new hosts file */
3496
			system_hosts_generate();
3497
		}
3498

    
3499
		if ($reloadall == true) {
3500

    
3501
			/* reconfigure static routes (kernel may have deleted them) */
3502
			system_routing_configure($interface);
3503

    
3504
			/* reload ipsec tunnels */
3505
			send_event("service reload ipsecdns");
3506

    
3507
			if (isset($config['dnsmasq']['enable'])) {
3508
				services_dnsmasq_configure();
3509
			}
3510

    
3511
			if (isset($config['unbound']['enable'])) {
3512
				services_unbound_configure();
3513
			}
3514

    
3515
			/* update dyndns */
3516
			send_event("service reload dyndns {$interface}");
3517

    
3518
			/* reload captive portal */
3519
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3520
				require_once('captiveportal.inc');
3521
			}
3522
			captiveportal_init_rules_byinterface($interface);
3523
		}
3524
	}
3525

    
3526
	interfaces_staticarp_configure($interface);
3527
	return 0;
3528
}
3529

    
3530
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3531
	global $config, $g;
3532

    
3533
	if (!is_array($wancfg)) {
3534
		return;
3535
	}
3536

    
3537
	if (!isset($wancfg['enable'])) {
3538
		return;
3539
	}
3540

    
3541
	/* If the interface is not configured via another, exit */
3542
	if (empty($wancfg['track6-interface'])) {
3543
		return;
3544
	}
3545

    
3546
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3547
	$realif = get_real_interface($interface);
3548
	$linklocal = find_interface_ipv6_ll($realif, true);
3549
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
3550
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3551
	}
3552
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3553
	/* XXX: Probably should remove? */
3554
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3555

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

    
3562
	switch ($trackcfg['ipaddrv6']) {
3563
		case "6to4":
3564
			if ($g['debug']) {
3565
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3566
			}
3567
			interface_track6_6to4_configure($interface, $wancfg);
3568
			break;
3569
		case "6rd":
3570
			if ($g['debug']) {
3571
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
3572
			}
3573
			interface_track6_6rd_configure($interface, $wancfg);
3574
			break;
3575
		case "dhcp6":
3576
			if ($linkupevent == true) {
3577
				/*
3578
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3579
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3580
				 *
3581
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3582
				 */
3583
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3584
				$pidv6 = find_dhcp6c_process($parentrealif);
3585
				if ($pidv6) {
3586
					posix_kill($pidv6, SIGHUP);
3587
				}
3588
			}
3589
			break;
3590
	}
3591

    
3592
	if ($linkupevent == false && !platform_booting()) {
3593
		if (!function_exists('services_dhcpd_configure')) {
3594
			require_once("services.inc");
3595
		}
3596

    
3597
		/* restart dns servers (defering dhcpd reload) */
3598
		if (isset($config['unbound']['enable'])) {
3599
			services_unbound_configure(false);
3600
		}
3601
		if (isset($config['dnsmasq']['enable'])) {
3602
			services_dnsmasq_configure(false);
3603
		}
3604

    
3605
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3606
		services_dhcpd_configure("inet6");
3607
	}
3608

    
3609
	return 0;
3610
}
3611

    
3612
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3613
	global $config, $g;
3614
	global $interface_ipv6_arr_cache;
3615
	global $interface_snv6_arr_cache;
3616

    
3617
	if (!is_array($lancfg)) {
3618
		return;
3619
	}
3620

    
3621
	/* If the interface is not configured via another, exit */
3622
	if (empty($lancfg['track6-interface'])) {
3623
		return;
3624
	}
3625

    
3626
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3627
	if (empty($wancfg)) {
3628
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3629
		return;
3630
	}
3631

    
3632
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3633
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3634
		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']));
3635
		return;
3636
	}
3637
	$hexwanv4 = return_hex_ipv4($ip4address);
3638

    
3639
	/* create the long prefix notation for math, save the prefix length */
3640
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3641
	$rd6prefixlen = $rd6prefix[1];
3642
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3643

    
3644
	/* binary presentation of the prefix for all 128 bits. */
3645
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3646

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

    
3652
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3653
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3654
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3655
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3656
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3657
	/* fill the rest out with zeros */
3658
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3659

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

    
3663
	$lanif = get_real_interface($interface);
3664
	$oip = find_interface_ipv6($lanif);
3665
	if (is_ipaddrv6($oip)) {
3666
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3667
	}
3668
	unset($interface_ipv6_arr_cache[$lanif]);
3669
	unset($interface_snv6_arr_cache[$lanif]);
3670
	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));
3671
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3672

    
3673
	return 0;
3674
}
3675

    
3676
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3677
	global $config, $g;
3678
	global $interface_ipv6_arr_cache;
3679
	global $interface_snv6_arr_cache;
3680

    
3681
	if (!is_array($lancfg)) {
3682
		return;
3683
	}
3684

    
3685
	/* If the interface is not configured via another, exit */
3686
	if (empty($lancfg['track6-interface'])) {
3687
		return;
3688
	}
3689

    
3690
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3691
	if (empty($wancfg)) {
3692
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3693
		return;
3694
	}
3695

    
3696
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3697
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3698
		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']));
3699
		return;
3700
	}
3701
	$hexwanv4 = return_hex_ipv4($ip4address);
3702

    
3703
	/* create the long prefix notation for math, save the prefix length */
3704
	$sixto4prefix = "2002::";
3705
	$sixto4prefixlen = 16;
3706
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3707

    
3708
	/* binary presentation of the prefix for all 128 bits. */
3709
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3710

    
3711
	/* just save the left prefix length bits */
3712
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3713
	/* add the v4 address */
3714
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3715
	/* add the custom prefix id */
3716
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3717
	/* fill the rest out with zeros */
3718
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3719

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

    
3723
	$lanif = get_real_interface($interface);
3724
	$oip = find_interface_ipv6($lanif);
3725
	if (is_ipaddrv6($oip)) {
3726
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3727
	}
3728
	unset($interface_ipv6_arr_cache[$lanif]);
3729
	unset($interface_snv6_arr_cache[$lanif]);
3730
	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));
3731
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3732

    
3733
	return 0;
3734
}
3735

    
3736
function interface_6rd_configure($interface = "wan", $wancfg) {
3737
	global $config, $g;
3738

    
3739
	/* because this is a tunnel interface we can only function
3740
	 *	with a public IPv4 address on the interface */
3741

    
3742
	if (!is_array($wancfg)) {
3743
		return;
3744
	}
3745

    
3746
	if (!is_module_loaded('if_stf.ko')) {
3747
		mwexec('/sbin/kldload if_stf.ko');
3748
	}
3749

    
3750
	$wanif = get_real_interface($interface);
3751
	$ip4address = find_interface_ip($wanif);
3752
	if (!is_ipaddrv4($ip4address)) {
3753
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3754
		return false;
3755
	}
3756
	$hexwanv4 = return_hex_ipv4($ip4address);
3757

    
3758
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3759
		$wancfg['prefix-6rd-v4plen'] = 0;
3760
	}
3761

    
3762
	/* create the long prefix notation for math, save the prefix length */
3763
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3764
	$rd6prefixlen = $rd6prefix[1];
3765
	$brgw = explode('.', $wancfg['gateway-6rd']);
3766
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
3767
	$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);
3768
	if (strlen($rd6brgw) < 128) {
3769
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3770
	}
3771
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
3772
	unset($brgw);
3773
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3774

    
3775
	/* binary presentation of the prefix for all 128 bits. */
3776
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3777

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

    
3785
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3786
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3787

    
3788

    
3789
	/* XXX: need to extend to support variable prefix size for v4 */
3790
	if (!is_module_loaded("if_stf")) {
3791
		mwexec("/sbin/kldload if_stf.ko");
3792
	}
3793
	$stfiface = "{$interface}_stf";
3794
	if (does_interface_exist($stfiface)) {
3795
		pfSense_interface_destroy($stfiface);
3796
	}
3797
	$tmpstfiface = pfSense_interface_create("stf");
3798
	pfSense_interface_rename($tmpstfiface, $stfiface);
3799
	pfSense_interface_flags($stfiface, IFF_LINK2);
3800
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3801
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3802
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3803
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3804
	}
3805
	if ($g['debug']) {
3806
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3807
	}
3808

    
3809
	/* write out a default router file */
3810
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3811
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3812

    
3813
	$ip4gateway = get_interface_gateway($interface);
3814
	if (is_ipaddrv4($ip4gateway)) {
3815
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
3816
	}
3817

    
3818
	/* configure dependent interfaces */
3819
	if (!platform_booting()) {
3820
		link_interface_to_track6($interface, "update");
3821
	}
3822

    
3823
	return 0;
3824
}
3825

    
3826
function interface_6to4_configure($interface = "wan", $wancfg) {
3827
	global $config, $g;
3828

    
3829
	/* because this is a tunnel interface we can only function
3830
	 *	with a public IPv4 address on the interface */
3831

    
3832
	if (!is_array($wancfg)) {
3833
		return;
3834
	}
3835

    
3836
	$wanif = get_real_interface($interface);
3837
	$ip4address = find_interface_ip($wanif);
3838
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3839
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3840
		return false;
3841
	}
3842

    
3843
	/* create the long prefix notation for math, save the prefix length */
3844
	$stfprefixlen = 16;
3845
	$stfprefix = Net_IPv6::uncompress("2002::");
3846
	$stfarr = explode(":", $stfprefix);
3847
	$v4prefixlen = "0";
3848

    
3849
	/* we need the hex form of the interface IPv4 address */
3850
	$ip4arr = explode(".", $ip4address);
3851
	$hexwanv4 = "";
3852
	foreach ($ip4arr as $octet) {
3853
		$hexwanv4 .= sprintf("%02x", $octet);
3854
	}
3855

    
3856
	/* we need the hex form of the broker IPv4 address */
3857
	$ip4arr = explode(".", "192.88.99.1");
3858
	$hexbrv4 = "";
3859
	foreach ($ip4arr as $octet) {
3860
		$hexbrv4 .= sprintf("%02x", $octet);
3861
	}
3862

    
3863
	/* binary presentation of the prefix for all 128 bits. */
3864
	$stfprefixbin = "";
3865
	foreach ($stfarr as $element) {
3866
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3867
	}
3868
	/* just save the left prefix length bits */
3869
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3870

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

    
3875
	/* for the local subnet too. */
3876
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3877
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3878

    
3879
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3880
	$stfbrarr = array();
3881
	$stfbrbinarr = array();
3882
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3883
	foreach ($stfbrbinarr as $bin) {
3884
		$stfbrarr[] = dechex(bindec($bin));
3885
	}
3886
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
3887

    
3888
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3889
	$stflanarr = array();
3890
	$stflanbinarr = array();
3891
	$stflanbinarr = str_split($stflanbin, 16);
3892
	foreach ($stflanbinarr as $bin) {
3893
		$stflanarr[] = dechex(bindec($bin));
3894
	}
3895
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
3896
	$stflanarr[7] = 1;
3897
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
3898

    
3899
	/* setup the stf interface */
3900
	if (!is_module_loaded("if_stf")) {
3901
		mwexec("/sbin/kldload if_stf.ko");
3902
	}
3903
	$stfiface = "{$interface}_stf";
3904
	if (does_interface_exist($stfiface)) {
3905
		pfSense_interface_destroy($stfiface);
3906
	}
3907
	$tmpstfiface = pfSense_interface_create("stf");
3908
	pfSense_interface_rename($tmpstfiface, $stfiface);
3909
	pfSense_interface_flags($stfiface, IFF_LINK2);
3910
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3911

    
3912
	if ($g['debug']) {
3913
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3914
	}
3915

    
3916
	/* write out a default router file */
3917
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3918
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3919

    
3920
	$ip4gateway = get_interface_gateway($interface);
3921
	if (is_ipaddrv4($ip4gateway)) {
3922
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
3923
	}
3924

    
3925
	if (!platform_booting()) {
3926
		link_interface_to_track6($interface, "update");
3927
	}
3928

    
3929
	return 0;
3930
}
3931

    
3932
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3933
	global $config, $g;
3934

    
3935
	if (!is_array($wancfg)) {
3936
		return;
3937
	}
3938

    
3939
	$wanif = get_real_interface($interface, "inet6");
3940
	$dhcp6cconf = "";
3941

    
3942
	if (!empty($config['system']['global-v6duid'])) {
3943
		// Write the DUID file
3944
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
3945
		    log_error(gettext("Failed to write user DUID file!"));
3946
		}
3947
	}
3948

    
3949
	if ($wancfg['adv_dhcp6_config_file_override']) {
3950
		// DHCP6 Config File Override
3951
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3952
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3953
		// DHCP6 Config File Advanced
3954
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3955
	} else {
3956
		// DHCP6 Config File Basic
3957
		$dhcp6cconf .= "interface {$wanif} {\n";
3958

    
3959
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3960
		if ($wancfg['ipaddrv6'] == "slaac") {
3961
			$dhcp6cconf .= "\tinformation-only;\n";
3962
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3963
			$dhcp6cconf .= "\trequest domain-name;\n";
3964
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3965
			$dhcp6cconf .= "};\n";
3966
		} else {
3967
			$trackiflist = array();
3968
			$iflist = link_interface_to_track6($interface);
3969
			foreach ($iflist as $ifname => $ifcfg) {
3970
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3971
					$trackiflist[$ifname] = $ifcfg;
3972
				}
3973
			}
3974

    
3975
			/* skip address request if this is set */
3976
			if (!isset($wancfg['dhcp6prefixonly'])) {
3977
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3978
			}
3979
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3980
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3981
			}
3982

    
3983
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3984
			$dhcp6cconf .= "\trequest domain-name;\n";
3985

    
3986
			/*
3987
			 * dhcp6c will run different scripts depending on
3988
			 * whether dhcpwithoutra is set or unset.
3989
			 */
3990
			if (isset($wancfg['dhcp6withoutra'])) {
3991
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
3992
			} else {
3993
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3994
			}
3995
			$dhcp6cconf .= "};\n";
3996

    
3997
			if (!isset($wancfg['dhcp6prefixonly'])) {
3998
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3999
			}
4000

    
4001
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4002
				/* Setup the prefix delegation */
4003
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4004
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4005
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4006
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4007
				}
4008
				foreach ($trackiflist as $friendly => $ifcfg) {
4009
					if ($g['debug']) {
4010
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4011
					}
4012
					$realif = get_real_interface($friendly);
4013
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4014
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4015
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4016
					$dhcp6cconf .= "\t};\n";
4017
				}
4018
				unset($preflen, $iflist, $ifcfg, $ifname);
4019
				$dhcp6cconf .= "};\n";
4020
			}
4021
			unset($trackiflist);
4022
		}
4023
	}
4024

    
4025
	/* wide-dhcp6c works for now. */
4026
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4027
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4028
		unset($dhcp6cconf);
4029
		return 1;
4030
	}
4031
	unset($dhcp6cconf);
4032

    
4033
	/*
4034
	 * Script create for dhcp6withoutRA mode.
4035
	 * dhcp6c will launch rtsold. rtsold will then run the wan ipv6
4036
	 * configure
4037
	 */
4038
	$dhcp6cscriptwithoutra  = "#!/bin/sh\n";
4039
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4040
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4041
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4042
	// Need to pass params to  the final script
4043
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4044
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4045
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4046

    
4047
	if (!@file_put_contents(
4048
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4049
	    $dhcp6cscriptwithoutra)) {
4050
		printf("Error: cannot open " .
4051
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4052
		    "interface_dhcpv6_configure() for writing.\n");
4053
		unset($dhcp6cscriptwithoutra);
4054
		return 1;
4055
	}
4056
	unset($dhcp6cscriptwithoutra);
4057
	@chmod(
4058
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4059
	    0755);
4060

    
4061
	/*
4062
	 * Dual mode wan_dhcp6c script with variations depending on node
4063
	 * dhcp6 will run the wan ipv6 configure
4064
	 */
4065
	$dhcp6cscript  = "#!/bin/sh\n";
4066
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4067
	if (!isset($wancfg['dhcp6withoutra'])) {
4068
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4069
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4070
	} else {
4071
		// Need to get the paramaters from the dhcp6cwithoutRA run
4072
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4073
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4074
	}
4075
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4076
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4077
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4078
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4079
		unset($dhcp6cscript);
4080
		return 1;
4081
	}
4082
	unset($dhcp6cscript);
4083
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4084

    
4085
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4086
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4087

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

    
4094
	/* non ipoe Process */
4095
	if (!isset($wancfg['dhcp6withoutra'])) {
4096
		/*
4097
		 * We only want this script to run once, and if it runs twice
4098
		 * then do not launch dhcp6c again, this only happens if
4099
		 * dhcpwithoutra is not set.
4100
		 *
4101
		 * Check for a lock file, trying to prevent multiple instances
4102
		 * of dhcp6c being launched
4103
		 */
4104
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4105
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4106
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4107
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4108
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4109
		$rtsoldscript .= "\tfi\n";
4110
		/*
4111
		 * Create the lock file, trying to prevent multiple instances
4112
		 * of dhcp6c being launched
4113
		 */
4114
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4115
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4116
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4117
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4118
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4119
		$rtsoldscript .= "else\n";
4120
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place\"\n";
4121
		$rtsoldscript .= "fi\n";
4122
	} else {
4123
		/*
4124
		 * The script needs to run in dhcp6withoutra mode as RA may
4125
		 * not have been received, or there can be a delay with
4126
		 * certain ISPs
4127
		 */
4128
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4129
		$rtsoldscript .= "/bin/sleep 1\n";
4130
	}
4131
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4132
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4133
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4134
		unset($rtsoldscript);
4135
		return 1;
4136
	}
4137
	unset($rtsoldscript);
4138
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4139

    
4140
	/* accept router advertisements for this interface */
4141
	log_error("Accept router advertisements on interface {$wanif} ");
4142
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4143

    
4144
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4145
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4146
		sleep(2);
4147
	}
4148

    
4149
	if (isset($wancfg['dhcp6withoutra'])) {
4150
		/*
4151
		 * Start dhcp6c here if we don't want to wait for ra - calls
4152
		 * seperate function
4153
		 *
4154
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4155
		 * will then run the configure on receipt of the RA.
4156
		 *
4157
		 * Already started. interface_dhcpv6_configure() appears to get
4158
		 * called multiple times.
4159
		 *
4160
		 * Taking the interface down or releasing will kill the client.
4161
		 */
4162
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4163
		{
4164
			/*
4165
			 * If the interface is being brought up, wait for the
4166
			 * interface to configure accept RA before launching.
4167
			 * Otherwise it is not ready to accept and will fail.
4168
			 */
4169
			sleep(3);
4170
			run_dhcp6client_process($wanif,$wancfg);
4171
		}
4172
	} else {
4173
		/*
4174
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4175
		 * ( it does not background, it exits! ) It will launch dhcp6c
4176
		 * if dhcpwihtoutra is not set
4177
		 */
4178
		mwexec("/usr/sbin/rtsold -1 " .
4179
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4180
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4181
		    $wanif);
4182
	}
4183
	/*
4184
	 * NOTE: will be called from rtsold invoked script
4185
	 * link_interface_to_track6($interface, "update");
4186
	 */
4187

    
4188
	return 0;
4189
}
4190

    
4191
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4192
	global $g;
4193

    
4194
	$send_options = "";
4195
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4196
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4197
		foreach ($options as $option) {
4198
			$send_options .= "\tsend " . trim($option) . ";\n";
4199
		}
4200
	}
4201

    
4202
	$request_options = "";
4203
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4204
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4205
		foreach ($options as $option) {
4206
			$request_options .= "\trequest " . trim($option) . ";\n";
4207
		}
4208
	}
4209

    
4210
	$information_only = "";
4211
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4212
		$information_only = "\tinformation-only;\n";
4213
	}
4214

    
4215
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4216
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4217
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4218
	}
4219

    
4220
	$interface_statement  = "interface";
4221
	$interface_statement .= " {$wanif}";
4222
	$interface_statement .= " {\n";
4223
	$interface_statement .= "$send_options";
4224
	$interface_statement .= "$request_options";
4225
	$interface_statement .= "$information_only";
4226
	$interface_statement .= "$script";
4227
	$interface_statement .= "};\n";
4228

    
4229
	$id_assoc_statement_address = "";
4230
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4231
		$id_assoc_statement_address .= "id-assoc";
4232
		$id_assoc_statement_address .= " na";
4233
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4234
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4235
		}
4236
		$id_assoc_statement_address .= " { ";
4237

    
4238
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4239
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4240
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4241
			$id_assoc_statement_address .= "\n\taddress";
4242
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4243
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4244
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4245
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4246
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4247
			}
4248
			$id_assoc_statement_address .= ";\n";
4249
		}
4250

    
4251
		$id_assoc_statement_address .= "};\n";
4252
	}
4253

    
4254
	$id_assoc_statement_prefix = "";
4255
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4256
		$id_assoc_statement_prefix .= "id-assoc";
4257
		$id_assoc_statement_prefix .= " pd";
4258
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4259
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4260
		}
4261
		$id_assoc_statement_prefix .= " { ";
4262

    
4263
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4264
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4265
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4266
			$id_assoc_statement_prefix .= "\n\tprefix";
4267
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4268
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4269
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4270
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4271
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4272
			}
4273
			$id_assoc_statement_prefix .= ";";
4274
		}
4275

    
4276
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4277
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4278
			$id_assoc_statement_prefix .= " {$wanif}";
4279
			$id_assoc_statement_prefix .= " {\n";
4280
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4281
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4282
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4283
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4284
			}
4285
			$id_assoc_statement_prefix .= "\t};";
4286
		}
4287

    
4288
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4289
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4290
			$id_assoc_statement_prefix .= "\n";
4291
		}
4292

    
4293
		$id_assoc_statement_prefix .= "};\n";
4294
	}
4295

    
4296
	$authentication_statement = "";
4297
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4298
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4299
		$authentication_statement .= "authentication";
4300
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4301
		$authentication_statement .= " {\n";
4302
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4303
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4304
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4305
		}
4306
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4307
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4308
		}
4309
		$authentication_statement .= "};\n";
4310
	}
4311

    
4312
	$key_info_statement = "";
4313
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4314
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4315
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4316
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4317
		$key_info_statement .= "keyinfo";
4318
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4319
		$key_info_statement .= " {\n";
4320
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4321
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4322
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4323
		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'])) {
4324
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4325
		}
4326
		$key_info_statement .= "};\n";
4327
	}
4328

    
4329
	$dhcp6cconf  = $interface_statement;
4330
	$dhcp6cconf .= $id_assoc_statement_address;
4331
	$dhcp6cconf .= $id_assoc_statement_prefix;
4332
	$dhcp6cconf .= $authentication_statement;
4333
	$dhcp6cconf .= $key_info_statement;
4334

    
4335
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4336

    
4337
	return $dhcp6cconf;
4338
}
4339

    
4340

    
4341
function DHCP6_Config_File_Override($wancfg, $wanif) {
4342

    
4343
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4344

    
4345
	if ($dhcp6cconf === false) {
4346
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4347
		return '';
4348
	} else {
4349
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4350
	}
4351
}
4352

    
4353

    
4354
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4355

    
4356
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4357

    
4358
	return $dhcp6cconf;
4359
}
4360

    
4361

    
4362
function interface_dhcp_configure($interface = "wan") {
4363
	global $config, $g;
4364

    
4365
	$wancfg = $config['interfaces'][$interface];
4366
	$wanif = $wancfg['if'];
4367
	if (empty($wancfg)) {
4368
		$wancfg = array();
4369
	}
4370

    
4371
	/* generate dhclient_wan.conf */
4372
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4373
	if (!$fd) {
4374
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4375
		return 1;
4376
	}
4377

    
4378
	if ($wancfg['dhcphostname']) {
4379
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4380
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4381
	} else {
4382
		$dhclientconf_hostname = "";
4383
	}
4384

    
4385
	$wanif = get_real_interface($interface);
4386
	if (empty($wanif)) {
4387
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4388
		return 0;
4389
	}
4390
	$dhclientconf = "";
4391

    
4392
	$dhclientconf .= <<<EOD
4393
interface "{$wanif}" {
4394
timeout 60;
4395
retry 15;
4396
select-timeout 0;
4397
initial-interval 1;
4398
	{$dhclientconf_hostname}
4399
	script "/usr/local/sbin/pfSense-dhclient-script";
4400
EOD;
4401

    
4402
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4403
		$dhclientconf .= <<<EOD
4404

    
4405
	reject {$wancfg['dhcprejectfrom']};
4406
EOD;
4407
	}
4408
	$dhclientconf .= <<<EOD
4409

    
4410
}
4411

    
4412
EOD;
4413

    
4414
	// DHCP Config File Advanced
4415
	if ($wancfg['adv_dhcp_config_advanced']) {
4416
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4417
	}
4418

    
4419
	if (is_ipaddr($wancfg['alias-address'])) {
4420
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4421
		$dhclientconf .= <<<EOD
4422
alias {
4423
	interface "{$wanif}";
4424
	fixed-address {$wancfg['alias-address']};
4425
	option subnet-mask {$subnetmask};
4426
}
4427

    
4428
EOD;
4429
	}
4430

    
4431
	// DHCP Config File Override
4432
	if ($wancfg['adv_dhcp_config_file_override']) {
4433
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4434
	}
4435

    
4436
	fwrite($fd, $dhclientconf);
4437
	fclose($fd);
4438

    
4439
	/* bring wan interface up before starting dhclient */
4440
	if ($wanif) {
4441
		interfaces_bring_up($wanif);
4442
	} else {
4443
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4444
	}
4445

    
4446
	/* Make sure dhclient is not running */
4447
	kill_dhclient_process($wanif);
4448

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

    
4452
	return 0;
4453
}
4454

    
4455
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4456

    
4457
	$hostname = "";
4458
	if ($wancfg['dhcphostname'] != '') {
4459
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4460
	}
4461

    
4462
	/* DHCP Protocol Timings */
4463
	$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");
4464
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4465
		$pt_variable = "{$Protocol_Timing}";
4466
		${$pt_variable} = "";
4467
		if ($wancfg[$Protocol_Timing] != "") {
4468
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4469
		}
4470
	}
4471

    
4472
	$send_options = "";
4473
	if ($wancfg['adv_dhcp_send_options'] != '') {
4474
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4475
		foreach ($options as $option) {
4476
			$send_options .= "\tsend " . trim($option) . ";\n";
4477
		}
4478
	}
4479

    
4480
	$request_options = "";
4481
	if ($wancfg['adv_dhcp_request_options'] != '') {
4482
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4483
	}
4484

    
4485
	$required_options = "";
4486
	if ($wancfg['adv_dhcp_required_options'] != '') {
4487
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4488
	}
4489

    
4490
	$option_modifiers = "";
4491
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4492
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4493
		foreach ($modifiers as $modifier) {
4494
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4495
		}
4496
	}
4497

    
4498
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4499
	$dhclientconf .= "\n";
4500
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4501
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4502
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4503
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4504
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4505
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4506
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4507
	$dhclientconf .= "\n";
4508
	$dhclientconf .= "# DHCP Protocol Options\n";
4509
	$dhclientconf .= "{$hostname}";
4510
	$dhclientconf .= "{$send_options}";
4511
	$dhclientconf .= "{$request_options}";
4512
	$dhclientconf .= "{$required_options}";
4513
	$dhclientconf .= "{$option_modifiers}";
4514
	$dhclientconf .= "\n";
4515
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4516
		$dhclientconf .= "reject {$wancfg['dhcprejectfrom']};\n";
4517
	}
4518
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
4519
	$dhclientconf .= "}\n";
4520

    
4521
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4522

    
4523
	return $dhclientconf;
4524
}
4525

    
4526
function DHCP_Config_Option_Split($option_string) {
4527
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4528
	return $matches ? $matches[0] : [];
4529
}
4530

    
4531
function DHCP_Config_File_Override($wancfg, $wanif) {
4532

    
4533
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4534

    
4535
	if ($dhclientconf === false) {
4536
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $wancfg['adv_dhcp_config_file_override_path']));
4537
		return '';
4538
	} else {
4539
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4540
	}
4541
}
4542

    
4543

    
4544
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4545

    
4546
	/* Apply Interface Substitutions */
4547
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4548

    
4549
	/* Apply Hostname Substitutions */
4550
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4551

    
4552
	/* Arrays of MAC Address Types, Cases, Delimiters */
4553
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4554
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4555
	$various_mac_cases      = array("U", "L");
4556
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4557

    
4558
	/* Apply MAC Address Substitutions */
4559
	foreach ($various_mac_types as $various_mac_type) {
4560
		foreach ($various_mac_cases as $various_mac_case) {
4561
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4562

    
4563
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4564
				if ($res !== false) {
4565

    
4566
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4567
					if ("$various_mac_case" == "U") {
4568
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4569
					}
4570
					if ("$various_mac_case" == "L") {
4571
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4572
					}
4573

    
4574
					if ("$various_mac_type" == "mac_addr_hex") {
4575
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4576
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4577
						$dhcpclientconf_mac_hex = "";
4578
						$delimiter = "";
4579
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4580
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4581
							$delimiter = ":";
4582
						}
4583
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4584
					}
4585

    
4586
					/* MAC Address Delimiter Substitutions */
4587
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4588

    
4589
					/* Apply MAC Address Substitutions */
4590
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4591
				}
4592
			}
4593
		}
4594
	}
4595

    
4596
	return $dhclientconf;
4597
}
4598

    
4599
function interfaces_group_setup() {
4600
	global $config;
4601

    
4602
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4603
		return;
4604
	}
4605

    
4606
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4607
		interface_group_setup($groupar);
4608
	}
4609

    
4610
	return;
4611
}
4612

    
4613
function interface_group_setup(&$groupname /* The parameter is an array */) {
4614
	global $config;
4615

    
4616
	if (!is_array($groupname)) {
4617
		return;
4618
	}
4619
	$members = explode(" ", $groupname['members']);
4620
	foreach ($members as $ifs) {
4621
		$realif = get_real_interface($ifs);
4622
		if ($realif && does_interface_exist($realif)) {
4623
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4624
		}
4625
	}
4626

    
4627
	return;
4628
}
4629

    
4630
function is_interface_group($if) {
4631
	global $config;
4632

    
4633
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4634
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4635
			if ($groupentry['ifname'] === $if) {
4636
				return true;
4637
			}
4638
		}
4639
	}
4640

    
4641
	return false;
4642
}
4643

    
4644
function interface_group_add_member($interface, $groupname) {
4645
	$interface = get_real_interface($interface);
4646
	if (does_interface_exist($interface)) {
4647
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4648
	}
4649
}
4650

    
4651
/* COMPAT Function */
4652
function convert_friendly_interface_to_real_interface_name($interface) {
4653
	return get_real_interface($interface);
4654
}
4655

    
4656
/* COMPAT Function */
4657
function get_real_wan_interface($interface = "wan") {
4658
	return get_real_interface($interface);
4659
}
4660

    
4661
/* COMPAT Function */
4662
function get_current_wan_address($interface = "wan") {
4663
	return get_interface_ip($interface);
4664
}
4665

    
4666
/*
4667
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4668
 */
4669
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4670
	global $config;
4671

    
4672
	/* XXX: For speed reasons reference directly the interface array */
4673
	$ifdescrs = &$config['interfaces'];
4674
	//$ifdescrs = get_configured_interface_list(false, true);
4675

    
4676
	foreach ($ifdescrs as $if => $ifname) {
4677
		if ($if == $interface || $ifname['if'] == $interface) {
4678
			return $if;
4679
		}
4680

    
4681
		if (get_real_interface($if) == $interface) {
4682
			return $if;
4683
		}
4684

    
4685
		if ($checkparent == false) {
4686
			continue;
4687
		}
4688

    
4689
		$int = get_parent_interface($if, true);
4690
		if (is_array($int)) {
4691
			foreach ($int as $iface) {
4692
				if ($iface == $interface) {
4693
					return $if;
4694
				}
4695
			}
4696
		}
4697
	}
4698

    
4699
	if ($interface == "enc0") {
4700
		return 'IPsec';
4701
	}
4702
}
4703

    
4704
/* attempt to resolve interface to friendly descr */
4705
function convert_friendly_interface_to_friendly_descr($interface) {
4706
	global $config;
4707

    
4708
	switch ($interface) {
4709
		case "l2tp":
4710
			$ifdesc = "L2TP";
4711
			break;
4712
		case "pptp":
4713
			$ifdesc = "PPTP";
4714
			break;
4715
		case "pppoe":
4716
			$ifdesc = "PPPoE";
4717
			break;
4718
		case "openvpn":
4719
			$ifdesc = "OpenVPN";
4720
			break;
4721
		case "lo0":
4722
			$ifdesc = "Loopback";
4723
			break;
4724
		case "enc0":
4725
		case "ipsec":
4726
		case "IPsec":
4727
			$ifdesc = "IPsec";
4728
			break;
4729
		default:
4730
			if (isset($config['interfaces'][$interface])) {
4731
				if (empty($config['interfaces'][$interface]['descr'])) {
4732
					$ifdesc = strtoupper($interface);
4733
				} else {
4734
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4735
				}
4736
				break;
4737
			} else if (substr($interface, 0, 4) == '_vip') {
4738
				if (is_array($config['virtualip']['vip'])) {
4739
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4740
						if ($vip['mode'] == "carp") {
4741
							if ($interface == "_vip{$vip['uniqid']}") {
4742
								return "{$vip['subnet']} - {$vip['descr']}";
4743
							}
4744
						}
4745
					}
4746
				}
4747
			} else if (substr($interface, 0, 5) == '_lloc') {
4748
				return get_interface_linklocal($interface);
4749
			} else {
4750
				/* if list */
4751
				$ifdescrs = get_configured_interface_with_descr(false, true);
4752
				foreach ($ifdescrs as $if => $ifname) {
4753
					if ($if == $interface || $ifname == $interface) {
4754
						return $ifname;
4755
					}
4756
				}
4757
			}
4758
			break;
4759
	}
4760

    
4761
	return $ifdesc;
4762
}
4763

    
4764
function convert_real_interface_to_friendly_descr($interface) {
4765

    
4766
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4767

    
4768
	if (!empty($ifdesc)) {
4769
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4770
	}
4771

    
4772
	return $interface;
4773
}
4774

    
4775
/*
4776
 *  get_parent_interface($interface):
4777
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4778
 *				or virtual interface (i.e. vlan)
4779
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4780
 *			-- returns $interface passed in if $interface parent is not found
4781
 *			-- returns empty array if an invalid interface is passed
4782
 *	(Only handles ppps and vlans now.)
4783
 */
4784
function get_parent_interface($interface, $avoidrecurse = false) {
4785
	global $config;
4786

    
4787
	$parents = array();
4788
	//Check that we got a valid interface passed
4789
	$realif = get_real_interface($interface);
4790
	if ($realif == NULL) {
4791
		return $parents;
4792
	}
4793

    
4794
	// If we got a real interface, find it's friendly assigned name
4795
	if ($interface == $realif && $avoidrecurse == false) {
4796
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4797
	}
4798

    
4799
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4800
		$ifcfg = $config['interfaces'][$interface];
4801
		switch ($ifcfg['ipaddr']) {
4802
			case "ppp":
4803
			case "pppoe":
4804
			case "pptp":
4805
			case "l2tp":
4806
				if (empty($parents)) {
4807
					if (is_array($config['ppps']['ppp'])) {
4808
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4809
							if ($ifcfg['if'] == $ppp['if']) {
4810
								$ports = explode(',', $ppp['ports']);
4811
								foreach ($ports as $pid => $parent_if) {
4812
									$parents[$pid] = get_real_interface($parent_if);
4813
								}
4814
								break;
4815
							}
4816
						}
4817
					}
4818
				}
4819
				break;
4820
			case "dhcp":
4821
			case "static":
4822
			default:
4823
				// Handle _vlans
4824
				if (strpos($realif, '_vlan') !== FALSE) {
4825
					if (is_array($config['vlans']['vlan'])) {
4826
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4827
							if ($ifcfg['if'] == $vlan['vlanif']) {
4828
								$parents[0] = $vlan['if'];
4829
								break;
4830
							}
4831
						}
4832
					}
4833
				}
4834
				break;
4835
		}
4836
	}
4837

    
4838
	if (empty($parents)) {
4839
		// Handle _vlans not assigned to an interface
4840
		if (strpos($realif, '_vlan') !== FALSE) {
4841
			if (is_array($config['vlans']['vlan'])) {
4842
				foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4843
					if ($realif == $vlan['vlanif']) {
4844
						$parents[0] = $vlan['if'];
4845
						break;
4846
					}
4847
				}
4848
			}
4849
		}
4850
	}
4851

    
4852
	if (empty($parents)) {
4853
		$parents[0] = $realif;
4854
	}
4855

    
4856
	return $parents;
4857
}
4858

    
4859
/*
4860
 *  get_parent_physical_interface($interface):
4861
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
4862
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
4863
 */
4864
function get_parent_physical_interface($interface) {
4865
	global $config;
4866

    
4867
	$realif = get_parent_interface($interface);
4868

    
4869
	if (substr($realif[0], 0, 4) == "lagg") {
4870
		foreach ($config['laggs']['lagg'] as $lagg) {
4871
			if ($realif[0] == $lagg['laggif']) {
4872
				return explode(",", $lagg['members']);
4873
			}
4874
		}
4875
	} else {
4876
		return $realif;
4877
	}
4878
}
4879

    
4880
function interface_is_wireless_clone($wlif) {
4881
	if (!stristr($wlif, "_wlan")) {
4882
		return false;
4883
	} else {
4884
		return true;
4885
	}
4886
}
4887

    
4888
function interface_get_wireless_base($wlif) {
4889
	if (!stristr($wlif, "_wlan")) {
4890
		return $wlif;
4891
	} else {
4892
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4893
	}
4894
}
4895

    
4896
function interface_get_wireless_clone($wlif) {
4897
	if (!stristr($wlif, "_wlan")) {
4898
		return $wlif . "_wlan0";
4899
	} else {
4900
		return $wlif;
4901
	}
4902
}
4903

    
4904
function interface_list_wireless() {
4905
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
4906

    
4907
	$result = array();
4908
	foreach ($portlist as $port) {
4909
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
4910
			continue;
4911
		}
4912

    
4913
		$desc = $port . " ( " . get_single_sysctl(
4914
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
4915

    
4916
		$result[] = array(
4917
		    "if" => $port,
4918
		    "descr" => $desc
4919
		);
4920
	}
4921

    
4922
	return $result;
4923
}
4924

    
4925
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4926
	global $config, $g;
4927

    
4928
	$wanif = NULL;
4929

    
4930
	switch ($interface) {
4931
		case "l2tp":
4932
			$wanif = "l2tp";
4933
			break;
4934
		case "pptp":
4935
			$wanif = "pptp";
4936
			break;
4937
		case "pppoe":
4938
			$wanif = "pppoe";
4939
			break;
4940
		case "openvpn":
4941
			$wanif = "openvpn";
4942
			break;
4943
		case "IPsec":
4944
		case "ipsec":
4945
		case "enc0":
4946
			$wanif = "enc0";
4947
			break;
4948
		case "ppp":
4949
			$wanif = "ppp";
4950
			break;
4951
		default:
4952
			if (substr($interface, 0, 4) == '_vip') {
4953
				$wanif = get_configured_vip_interface($interface);
4954
				if (!empty($wanif)) {
4955
					$wanif = get_real_interface($wanif);
4956
				}
4957
				break;
4958
			} else if (substr($interface, 0, 5) == '_lloc') {
4959
				$interface = substr($interface, 5);
4960
			} else if (strstr($interface, "_vlan") ||
4961
			    does_interface_exist($interface, $flush)) {
4962
				/*
4963
				 * If a real interface was already passed simply
4964
				 * pass the real interface back.  This encourages
4965
				 * the usage of this function in more cases so that
4966
				 * we can combine logic for more flexibility.
4967
				 */
4968
				$wanif = $interface;
4969
				break;
4970
			}
4971

    
4972
			if (empty($config['interfaces'][$interface])) {
4973
				break;
4974
			}
4975

    
4976
			$cfg = &$config['interfaces'][$interface];
4977

    
4978
			if ($family == "inet6") {
4979
				switch ($cfg['ipaddrv6']) {
4980
					case "6rd":
4981
					case "6to4":
4982
						$wanif = "{$interface}_stf";
4983
						break;
4984
					case 'pppoe':
4985
					case 'ppp':
4986
					case 'l2tp':
4987
					case 'pptp':
4988
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4989
							$wanif = interface_get_wireless_clone($cfg['if']);
4990
						} else {
4991
							$wanif = $cfg['if'];
4992
						}
4993
						break;
4994
					default:
4995
						switch ($cfg['ipaddr']) {
4996
							case 'pppoe':
4997
							case 'ppp':
4998
							case 'l2tp':
4999
							case 'pptp':
5000
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
5001
									$wanif = $cfg['if'];
5002
								} else {
5003
									$parents = get_parent_interface($interface);
5004
									if (!empty($parents[0])) {
5005
										$wanif = $parents[0];
5006
									} else {
5007
										$wanif = $cfg['if'];
5008
									}
5009
								}
5010
								break;
5011
							default:
5012
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5013
									$wanif = interface_get_wireless_clone($cfg['if']);
5014
								} else {
5015
									$wanif = $cfg['if'];
5016
								}
5017
								break;
5018
						}
5019
						break;
5020
				}
5021
			} else {
5022
				// Wireless cloned NIC support (FreeBSD 8+)
5023
				// interface name format: $parentnic_wlanparentnic#
5024
				// example: ath0_wlan0
5025
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5026
					$wanif = interface_get_wireless_clone($cfg['if']);
5027
				} else {
5028
					$wanif = $cfg['if'];
5029
				}
5030
			}
5031
			break;
5032
	}
5033

    
5034
	return $wanif;
5035
}
5036

    
5037
/* Guess the physical interface by providing a IP address */
5038
function guess_interface_from_ip($ipaddress) {
5039

    
5040
	$family = '';
5041
	if (is_ipaddrv4($ipaddress)) {
5042
		$family = 'inet';
5043
	}
5044
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5045
		$family = 'inet6';
5046
	}
5047

    
5048
	if (empty($family)) {
5049
		return false;
5050
	}
5051

    
5052
	/* create a route table we can search */
5053
	$output = '';
5054
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5055
	$output[0] = trim($output[0], " \n");
5056
	if (!empty($output[0])) {
5057
		return $output[0];
5058
	}
5059

    
5060
	return false;
5061
}
5062

    
5063
/*
5064
 * find_ip_interface($ip): return the interface where an ip is defined
5065
 *   (or if $bits is specified, where an IP within the subnet is defined)
5066
 */
5067
function find_ip_interface($ip, $bits = null) {
5068
	if (!is_ipaddr($ip)) {
5069
		return false;
5070
	}
5071

    
5072
	$isv6ip = is_ipaddrv6($ip);
5073

    
5074
	/* if list */
5075
	$ifdescrs = get_configured_interface_list();
5076

    
5077
	foreach ($ifdescrs as $ifdescr => $ifname) {
5078
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5079
		if (is_null($ifip)) {
5080
			continue;
5081
		}
5082
		if (is_null($bits)) {
5083
			if ($ip == $ifip) {
5084
				$int = get_real_interface($ifname);
5085
				return $int;
5086
			}
5087
		} else {
5088
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5089
				$int = get_real_interface($ifname);
5090
				return $int;
5091
			}
5092
		}
5093
	}
5094

    
5095
	return false;
5096
}
5097

    
5098
/*
5099
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5100
 *   (or if $bits is specified, where an IP within the subnet is found)
5101
 */
5102
function find_virtual_ip_alias($ip, $bits = null) {
5103
	global $config;
5104

    
5105
	if (!is_array($config['virtualip']['vip'])) {
5106
		return false;
5107
	}
5108
	if (!is_ipaddr($ip)) {
5109
		return false;
5110
	}
5111

    
5112
	$isv6ip = is_ipaddrv6($ip);
5113

    
5114
	foreach ($config['virtualip']['vip'] as $vip) {
5115
		if ($vip['mode'] === "ipalias") {
5116
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5117
				continue;
5118
			}
5119
			if (is_null($bits)) {
5120
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5121
					return $vip;
5122
				}
5123
			} else {
5124
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5125
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5126
					return $vip;
5127
				}
5128
			}
5129
		}
5130
	}
5131
	return false;
5132
}
5133

    
5134
function link_interface_to_track6($int, $action = "") {
5135
	global $config;
5136

    
5137
	if (empty($int)) {
5138
		return;
5139
	}
5140

    
5141
	if (is_array($config['interfaces'])) {
5142
		$list = array();
5143
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5144
			if (!isset($ifcfg['enable'])) {
5145
				continue;
5146
			}
5147
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5148
				if ($action == "update") {
5149
					interface_track6_configure($ifname, $ifcfg);
5150
				} else if ($action == "") {
5151
					$list[$ifname] = $ifcfg;
5152
				}
5153
			}
5154
		}
5155
		return $list;
5156
	}
5157
}
5158

    
5159
function interface_find_child_cfgmtu($realiface) {
5160
	global $config;
5161

    
5162
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5163
	$vlans = link_interface_to_vlans($realiface);
5164
	$qinqs = link_interface_to_qinqs($realiface);
5165
	$bridge = link_interface_to_bridge($realiface);
5166
	if (!empty($interface)) {
5167
		$gifs = link_interface_to_gif($interface);
5168
		$gres = link_interface_to_gre($interface);
5169
	} else {
5170
		$gifs = array();
5171
		$gres = array();
5172
	}
5173

    
5174
	$mtu = 0;
5175
	if (is_array($vlans)) {
5176
		foreach ($vlans as $vlan) {
5177
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5178
			if (empty($ifass)) {
5179
				continue;
5180
			}
5181
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5182
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5183
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5184
				}
5185
			}
5186
		}
5187
	}
5188
	if (is_array($qinqs)) {
5189
		foreach ($qinqs as $qinq) {
5190
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5191
			if (empty($ifass)) {
5192
				continue;
5193
			}
5194
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5195
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5196
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5197
				}
5198
			}
5199
		}
5200
	}
5201
	if (is_array($gifs)) {
5202
		foreach ($gifs as $gif) {
5203
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5204
			if (empty($ifass)) {
5205
				continue;
5206
			}
5207
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5208
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5209
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5210
				}
5211
			}
5212
		}
5213
	}
5214
	if (is_array($gres)) {
5215
		foreach ($gres as $gre) {
5216
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5217
			if (empty($ifass)) {
5218
				continue;
5219
			}
5220
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5221
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5222
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5223
				}
5224
			}
5225
		}
5226
	}
5227
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5228
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5229
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5230
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5231
		}
5232
	}
5233
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5234

    
5235
	return $mtu;
5236
}
5237

    
5238
function link_interface_to_vlans($int, $action = "") {
5239
	global $config;
5240

    
5241
	if (empty($int)) {
5242
		return;
5243
	}
5244

    
5245
	if (is_array($config['vlans']['vlan'])) {
5246
		$ifaces = array();
5247
		foreach ($config['vlans']['vlan'] as $vlan) {
5248
			if ($int == $vlan['if']) {
5249
				if ($action == "update") {
5250
					interfaces_bring_up($int);
5251
				} else {
5252
					$ifaces[$vlan['tag']] = $vlan;
5253
				}
5254
			}
5255
		}
5256
		if (!empty($ifaces)) {
5257
			return $ifaces;
5258
		}
5259
	}
5260
}
5261

    
5262
function link_interface_to_qinqs($int, $action = "") {
5263
	global $config;
5264

    
5265
	if (empty($int)) {
5266
		return;
5267
	}
5268

    
5269
	if (is_array($config['qinqs']['qinqentry'])) {
5270
		$ifaces = array();
5271
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5272
			if ($int == $qinq['if']) {
5273
				if ($action == "update") {
5274
					interfaces_bring_up($int);
5275
				} else {
5276
					$ifaces[$qinq['tag']] = $qinq;
5277
				}
5278
			}
5279
		}
5280
		if (!empty($ifaces)) {
5281
			return $ifaces;
5282
		}
5283
	}
5284
}
5285

    
5286
function link_interface_to_vips($int, $action = "", $vhid = '') {
5287
	global $config;
5288

    
5289
	$updatevips = false;
5290
	if (is_array($config['virtualip']['vip'])) {
5291
		$result = array();
5292
		foreach ($config['virtualip']['vip'] as $vip) {
5293
			if (substr($vip['interface'], 0, 4) == "_vip") {
5294
				$iface = get_configured_vip_interface($vip['interface']);
5295
			} else {
5296
				$iface = $vip['interface'];
5297
			}
5298
			if ($int != $iface) {
5299
				continue;
5300
			}
5301
			if ($action == "update") {
5302
				$updatevips = true;
5303
			} else {
5304
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5305
				    substr($vip['interface'], 0, 4) == "_vip") {
5306
					$result[] = $vip;
5307
				}
5308
			}
5309
		}
5310
		if ($updatevips === true) {
5311
			interfaces_vips_configure($int);
5312
		}
5313
		return $result;
5314
	}
5315

    
5316
	return NULL;
5317
}
5318

    
5319
/****f* interfaces/link_interface_to_bridge
5320
 * NAME
5321
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5322
 * INPUTS
5323
 *   $ip
5324
 * RESULT
5325
 *   bridge[0-99]
5326
 ******/
5327
function link_interface_to_bridge($int) {
5328
	global $config;
5329

    
5330
	if (is_array($config['bridges']['bridged'])) {
5331
		foreach ($config['bridges']['bridged'] as $bridge) {
5332
			if (in_array($int, explode(',', $bridge['members']))) {
5333
				return "{$bridge['bridgeif']}";
5334
			}
5335
		}
5336
	}
5337
}
5338

    
5339
function link_interface_to_group($int) {
5340
	global $config;
5341

    
5342
	$result = array();
5343

    
5344
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5345
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5346
			if (in_array($int, explode(" ", $group['members']))) {
5347
				$result[$group['ifname']] = $int;
5348
			}
5349
		}
5350
	}
5351

    
5352
	return $result;
5353
}
5354

    
5355
function link_interface_to_gre($interface) {
5356
	global $config;
5357

    
5358
	$result = array();
5359

    
5360
	if (is_array($config['gres']['gre'])) {
5361
		foreach ($config['gres']['gre'] as $gre) {
5362
			if ($gre['if'] == $interface) {
5363
				$result[] = $gre;
5364
			}
5365
		}
5366
	}
5367

    
5368
	return $result;
5369
}
5370

    
5371
function link_interface_to_gif($interface) {
5372
	global $config;
5373

    
5374
	$result = array();
5375

    
5376
	if (is_array($config['gifs']['gif'])) {
5377
		foreach ($config['gifs']['gif'] as $gif) {
5378
			if ($gif['if'] == $interface) {
5379
				$result[] = $gif;
5380
			}
5381
		}
5382
	}
5383

    
5384
	return $result;
5385
}
5386

    
5387
/*
5388
 * find_interface_ip($interface): return the interface ip (first found)
5389
 */
5390
function find_interface_ip($interface, $flush = false) {
5391
	global $interface_ip_arr_cache;
5392
	global $interface_sn_arr_cache;
5393

    
5394
	$interface = str_replace("\n", "", $interface);
5395

    
5396
	if (!does_interface_exist($interface)) {
5397
		return;
5398
	}
5399

    
5400
	/* Setup IP cache */
5401
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5402
		if (file_exists("/var/db/${interface}_ip")) {
5403
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5404
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5405
			foreach ($ifaddrs as $ifaddr) {
5406
				list($ip, $mask) = explode("/", $ifaddr);
5407
				if ($ip == $ifip) {
5408
					$interface_ip_arr_cache[$interface] = $ip;
5409
					$interface_sn_arr_cache[$interface] = $mask;
5410
					break;
5411
				}
5412
			}
5413
		}
5414
		if (!isset($interface_ip_arr_cache[$interface])) {
5415
			$ifinfo = pfSense_get_interface_addresses($interface);
5416
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5417
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5418
		}
5419
	}
5420

    
5421
	return $interface_ip_arr_cache[$interface];
5422
}
5423

    
5424
/*
5425
 * find_interface_ipv6($interface): return the interface ip (first found)
5426
 */
5427
function find_interface_ipv6($interface, $flush = false) {
5428
	global $interface_ipv6_arr_cache;
5429
	global $interface_snv6_arr_cache;
5430
	global $config;
5431

    
5432
	$interface = trim($interface);
5433
	$interface = get_real_interface($interface);
5434

    
5435
	if (!does_interface_exist($interface)) {
5436
		return;
5437
	}
5438

    
5439
	/* Setup IP cache */
5440
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5441
		$ifinfo = pfSense_get_interface_addresses($interface);
5442
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5443
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5444
	}
5445

    
5446
	return $interface_ipv6_arr_cache[$interface];
5447
}
5448

    
5449
/*
5450
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5451
 */
5452
function find_interface_ipv6_ll($interface, $flush = false) {
5453
	global $interface_llv6_arr_cache;
5454
	global $config;
5455

    
5456
	$interface = str_replace("\n", "", $interface);
5457

    
5458
	if (!does_interface_exist($interface)) {
5459
		return;
5460
	}
5461

    
5462
	/* Setup IP cache */
5463
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5464
		$ifinfo = pfSense_getall_interface_addresses($interface);
5465
		foreach ($ifinfo as $line) {
5466
			if (strstr($line, ":")) {
5467
				$parts = explode("/", $line);
5468
				if (is_linklocal($parts[0])) {
5469
					$ifinfo['linklocal'] = $parts[0];
5470
				}
5471
			}
5472
		}
5473
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5474
	}
5475
	return $interface_llv6_arr_cache[$interface];
5476
}
5477

    
5478
function find_interface_subnet($interface, $flush = false) {
5479
	global $interface_sn_arr_cache;
5480
	global $interface_ip_arr_cache;
5481

    
5482
	$interface = str_replace("\n", "", $interface);
5483
	if (does_interface_exist($interface) == false) {
5484
		return;
5485
	}
5486

    
5487
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5488
		$ifinfo = pfSense_get_interface_addresses($interface);
5489
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5490
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5491
	}
5492

    
5493
	return $interface_sn_arr_cache[$interface];
5494
}
5495

    
5496
function find_interface_subnetv6($interface, $flush = false) {
5497
	global $interface_snv6_arr_cache;
5498
	global $interface_ipv6_arr_cache;
5499

    
5500
	$interface = str_replace("\n", "", $interface);
5501
	if (does_interface_exist($interface) == false) {
5502
		return;
5503
	}
5504

    
5505
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5506
		$ifinfo = pfSense_get_interface_addresses($interface);
5507
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5508
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5509
	}
5510

    
5511
	return $interface_snv6_arr_cache[$interface];
5512
}
5513

    
5514
function ip_in_interface_alias_subnet($interface, $ipalias) {
5515
	global $config;
5516

    
5517
	if (empty($interface) || !is_ipaddr($ipalias)) {
5518
		return false;
5519
	}
5520
	if (is_array($config['virtualip']['vip'])) {
5521
		foreach ($config['virtualip']['vip'] as $vip) {
5522
			switch ($vip['mode']) {
5523
				case "ipalias":
5524
					if ($vip['interface'] <> $interface) {
5525
						break;
5526
					}
5527
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5528
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5529
						return true;
5530
					}
5531
					break;
5532
			}
5533
		}
5534
	}
5535

    
5536
	return false;
5537
}
5538

    
5539
function get_possible_listen_ips($include_ipv6_link_local=false) {
5540

    
5541
	$interfaces = get_configured_interface_with_descr();
5542
	foreach ($interfaces as $iface => $ifacename) {
5543
		if ($include_ipv6_link_local) {
5544
			/* This is to avoid going though added ll below */
5545
			if (substr($iface, 0, 5) == '_lloc') {
5546
				continue;
5547
			}
5548
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5549
			if (!empty($llip)) {
5550
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5551
			}
5552
		}
5553
	}
5554
	$viplist = get_configured_vip_list();
5555
	foreach ($viplist as $vip => $address) {
5556
		$interfaces[$vip] = $address;
5557
		if (get_vip_descr($address)) {
5558
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5559
		}
5560
	}
5561

    
5562
	$interfaces['lo0'] = 'Localhost';
5563

    
5564
	return $interfaces;
5565
}
5566

    
5567
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5568
	global $config;
5569

    
5570
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5571
	foreach (array('server', 'client') as $mode) {
5572
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5573
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5574
				if (!isset($setting['disable'])) {
5575
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5576
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5577
				}
5578
			}
5579
		}
5580
	}
5581
	return $sourceips;
5582
}
5583

    
5584
function get_interface_ip($interface = "wan") {
5585

    
5586
	if (substr($interface, 0, 4) == '_vip') {
5587
		return get_configured_vip_ipv4($interface);
5588
	} else if (substr($interface, 0, 5) == '_lloc') {
5589
		/* No link-local address for v4. */
5590
		return null;
5591
	}
5592

    
5593
	$realif = get_failover_interface($interface, 'inet');
5594
	if (!$realif) {
5595
		return null;
5596
	}
5597

    
5598
	if (substr($realif, 0, 4) == '_vip') {
5599
		return get_configured_vip_ipv4($realif);
5600
	} else if (substr($realif, 0, 5) == '_lloc') {
5601
		/* No link-local address for v4. */
5602
		return null;
5603
	}
5604

    
5605
	if (is_array($config['interfaces'][$interface]) &&
5606
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5607
		return ($config['interfaces'][$interface]['ipaddr']);
5608
	}
5609

    
5610
	/*
5611
	 * Beaware that find_interface_ip() is our last option, it will
5612
	 * return the first IP it find on interface, not necessarily the
5613
	 * main IP address.
5614
	 */
5615
	$curip = find_interface_ip($realif);
5616
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5617
		return $curip;
5618
	} else {
5619
		return null;
5620
	}
5621
}
5622

    
5623
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5624
	global $config;
5625

    
5626
	if (substr($interface, 0, 4) == '_vip') {
5627
		return get_configured_vip_ipv6($interface);
5628
	} else if (substr($interface, 0, 5) == '_lloc') {
5629
		return get_interface_linklocal($interface);
5630
	}
5631

    
5632
	$realif = get_failover_interface($interface, 'inet6');
5633
	if (!$realif) {
5634
		return null;
5635
	}
5636

    
5637
	if (substr($realif, 0, 4) == '_vip') {
5638
		return get_configured_vip_ipv6($realif);
5639
	} else if (substr($realif, 0, 5) == '_lloc') {
5640
		return get_interface_linklocal($realif);
5641
	}
5642

    
5643
	if (is_array($config['interfaces'][$interface])) {
5644
		switch ($config['interfaces'][$interface]['ipaddr']) {
5645
			case 'pppoe':
5646
			case 'l2tp':
5647
			case 'pptp':
5648
			case 'ppp':
5649
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5650
					$realif = get_real_interface($interface, 'inet6', false);
5651
				}
5652
				break;
5653
		}
5654
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5655
			return ($config['interfaces'][$interface]['ipaddrv6']);
5656
		}
5657
	}
5658

    
5659
	/*
5660
	 * Beaware that find_interface_ip() is our last option, it will
5661
	 * return the first IP it find on interface, not necessarily the
5662
	 * main IP address.
5663
	 */
5664
	$curip = find_interface_ipv6($realif, $flush);
5665
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5666
		return $curip;
5667
	} else {
5668
		/*
5669
		 * NOTE: On the case when only the prefix is requested,
5670
		 * the communication on WAN will be done over link-local.
5671
		 */
5672
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5673
			$curip = find_interface_ipv6_ll($realif, $flush);
5674
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5675
				return $curip;
5676
			}
5677
		}
5678
	}
5679
	return null;
5680
}
5681

    
5682
function get_interface_linklocal($interface = "wan") {
5683

    
5684
	$realif = get_failover_interface($interface, 'inet6');
5685
	if (!$realif) {
5686
		return null;
5687
	}
5688

    
5689
	if (substr($interface, 0, 4) == '_vip') {
5690
		$realif = get_real_interface($interface);
5691
	} else if (substr($interface, 0, 5) == '_lloc') {
5692
		$realif = get_real_interface(substr($interface, 5));
5693
	}
5694

    
5695
	$curip = find_interface_ipv6_ll($realif);
5696
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5697
		return $curip;
5698
	} else {
5699
		return null;
5700
	}
5701
}
5702

    
5703
function get_interface_subnet($interface = "wan") {
5704

    
5705
	if (substr($interface, 0, 4) == '_vip') {
5706
		return (get_configured_vip_subnetv4($interface));
5707
	}
5708

    
5709
	$realif = get_real_interface($interface);
5710
	if (!$realif) {
5711
		return (NULL);
5712
	}
5713

    
5714
	$cursn = find_interface_subnet($realif);
5715
	if (!empty($cursn)) {
5716
		return ($cursn);
5717
	}
5718

    
5719
	return (NULL);
5720
}
5721

    
5722
function get_interface_subnetv6($interface = "wan") {
5723

    
5724
	if (substr($interface, 0, 4) == '_vip') {
5725
		return (get_configured_vip_subnetv6($interface));
5726
	} else if (substr($interface, 0, 5) == '_lloc') {
5727
		$interface = substr($interface, 5);
5728
	}
5729

    
5730
	$realif = get_real_interface($interface, 'inet6');
5731
	if (!$realif) {
5732
		return (NULL);
5733
	}
5734

    
5735
	$cursn = find_interface_subnetv6($realif);
5736
	if (!empty($cursn)) {
5737
		return ($cursn);
5738
	}
5739

    
5740
	return (NULL);
5741
}
5742

    
5743
/* return outside interfaces with a gateway */
5744
function get_interfaces_with_gateway() {
5745
	global $config;
5746

    
5747
	$ints = array();
5748

    
5749
	/* loop interfaces, check config for outbound */
5750
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5751
		switch ($ifname['ipaddr']) {
5752
			case "dhcp":
5753
			case "pppoe":
5754
			case "pptp":
5755
			case "l2tp":
5756
			case "ppp":
5757
				$ints[$ifdescr] = $ifdescr;
5758
				break;
5759
			default:
5760
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5761
				    !empty($ifname['gateway'])) {
5762
					$ints[$ifdescr] = $ifdescr;
5763
				}
5764
				break;
5765
		}
5766
	}
5767
	return $ints;
5768
}
5769

    
5770
/* return true if interface has a gateway */
5771
function interface_has_gateway($friendly) {
5772
	global $config;
5773

    
5774
	if (!empty($config['interfaces'][$friendly])) {
5775
		$ifname = &$config['interfaces'][$friendly];
5776
		switch ($ifname['ipaddr']) {
5777
			case "dhcp":
5778
			case "pppoe":
5779
			case "pptp":
5780
			case "l2tp":
5781
			case "ppp":
5782
				return true;
5783
			break;
5784
			default:
5785
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5786
					return true;
5787
				}
5788
				$tunnelif = substr($ifname['if'], 0, 3);
5789
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5790
					if (find_interface_ip($ifname['if'])) {
5791
						return true;
5792
					}
5793
				}
5794
				if (!empty($ifname['gateway'])) {
5795
					return true;
5796
				}
5797
			break;
5798
		}
5799
	}
5800

    
5801
	return false;
5802
}
5803

    
5804
/* return true if interface has a gateway */
5805
function interface_has_gatewayv6($friendly) {
5806
	global $config;
5807

    
5808
	if (!empty($config['interfaces'][$friendly])) {
5809
		$ifname = &$config['interfaces'][$friendly];
5810
		switch ($ifname['ipaddrv6']) {
5811
			case "slaac":
5812
			case "dhcp6":
5813
			case "6to4":
5814
			case "6rd":
5815
				return true;
5816
				break;
5817
			default:
5818
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5819
					return true;
5820
				}
5821
				$tunnelif = substr($ifname['if'], 0, 3);
5822
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5823
					if (find_interface_ipv6($ifname['if'])) {
5824
						return true;
5825
					}
5826
				}
5827
				if (!empty($ifname['gatewayv6'])) {
5828
					return true;
5829
				}
5830
				break;
5831
		}
5832
	}
5833

    
5834
	return false;
5835
}
5836

    
5837
/****f* interfaces/is_altq_capable
5838
 * NAME
5839
 *   is_altq_capable - Test if interface is capable of using ALTQ
5840
 * INPUTS
5841
 *   $int            - string containing interface name
5842
 * RESULT
5843
 *   boolean         - true or false
5844
 ******/
5845

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

    
5860
	$int_family = remove_ifindex($int);
5861

    
5862
	if (in_array($int_family, $capable)) {
5863
		return true;
5864
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5865
		return true;
5866
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5867
		return true;
5868
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5869
		return true;
5870
	} else {
5871
		return false;
5872
	}
5873
}
5874

    
5875
/****f* interfaces/is_interface_wireless
5876
 * NAME
5877
 *   is_interface_wireless - Returns if an interface is wireless
5878
 * RESULT
5879
 *   $tmp       - Returns if an interface is wireless
5880
 ******/
5881
function is_interface_wireless($interface) {
5882
	global $config, $g;
5883

    
5884
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5885
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5886
		if (preg_match($g['wireless_regex'], $interface)) {
5887
			if (isset($config['interfaces'][$friendly])) {
5888
				$config['interfaces'][$friendly]['wireless'] = array();
5889
			}
5890
			return true;
5891
		}
5892
		return false;
5893
	} else {
5894
		return true;
5895
	}
5896
}
5897

    
5898
function get_wireless_modes($interface) {
5899
	/* return wireless modes and channels */
5900
	$wireless_modes = array();
5901

    
5902
	$cloned_interface = get_real_interface($interface);
5903

    
5904
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5905
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5906
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5907
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5908

    
5909
		$interface_channels = "";
5910
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5911
		$interface_channel_count = count($interface_channels);
5912

    
5913
		$c = 0;
5914
		while ($c < $interface_channel_count) {
5915
			$channel_line = explode(",", $interface_channels["$c"]);
5916
			$wireless_mode = trim($channel_line[0]);
5917
			$wireless_channel = trim($channel_line[1]);
5918
			if (trim($wireless_mode) != "") {
5919
				/* if we only have 11g also set 11b channels */
5920
				if ($wireless_mode == "11g") {
5921
					if (!isset($wireless_modes["11b"])) {
5922
						$wireless_modes["11b"] = array();
5923
					}
5924
				} else if ($wireless_mode == "11g ht") {
5925
					if (!isset($wireless_modes["11b"])) {
5926
						$wireless_modes["11b"] = array();
5927
					}
5928
					if (!isset($wireless_modes["11g"])) {
5929
						$wireless_modes["11g"] = array();
5930
					}
5931
					$wireless_mode = "11ng";
5932
				} else if ($wireless_mode == "11a ht") {
5933
					if (!isset($wireless_modes["11a"])) {
5934
						$wireless_modes["11a"] = array();
5935
					}
5936
					$wireless_mode = "11na";
5937
				}
5938
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5939
			}
5940
			$c++;
5941
		}
5942
	}
5943
	return($wireless_modes);
5944
}
5945

    
5946
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5947
function get_wireless_channel_info($interface) {
5948
	$wireless_channels = array();
5949

    
5950
	$cloned_interface = get_real_interface($interface);
5951

    
5952
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5953
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5954
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5955
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5956

    
5957
		$interface_channels = "";
5958
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5959

    
5960
		foreach ($interface_channels as $channel_line) {
5961
			$channel_line = explode(",", $channel_line);
5962
			if (!isset($wireless_channels[$channel_line[0]])) {
5963
				$wireless_channels[$channel_line[0]] = $channel_line;
5964
			}
5965
		}
5966
	}
5967
	return($wireless_channels);
5968
}
5969

    
5970
function set_interface_mtu($interface, $mtu) {
5971

    
5972
	/* LAGG interface must be destroyed and re-created to change MTU */
5973
	if (substr($interface, 0, 4) == 'lagg') {
5974
		if (isset($config['laggs']['lagg']) &&
5975
		    is_array($config['laggs']['lagg'])) {
5976
			foreach ($config['laggs']['lagg'] as $lagg) {
5977
				if ($lagg['laggif'] == $interface) {
5978
					interface_lagg_configure($lagg);
5979
					break;
5980
				}
5981
			}
5982
		}
5983
	} else {
5984
		pfSense_interface_mtu($interface, $mtu);
5985
	}
5986
}
5987

    
5988
/****f* interfaces/get_interface_mtu
5989
 * NAME
5990
 *   get_interface_mtu - Return the mtu of an interface
5991
 * RESULT
5992
 *   $tmp       - Returns the mtu of an interface
5993
 ******/
5994
function get_interface_mtu($interface) {
5995
	$mtu = pfSense_interface_getmtu($interface);
5996
	return $mtu['mtu'];
5997
}
5998

    
5999
function get_interface_mac($interface) {
6000
	$macinfo = pfSense_get_interface_addresses($interface);
6001
	return $macinfo["macaddr"];
6002
}
6003

    
6004
function get_interface_vendor_mac($interface) {
6005
	global $g;
6006

    
6007
	$mac = "";
6008
	$mac_file = "{$g['vardb_path']}/vendor_mac";
6009
	if (file_exists($mac_file)) {
6010
		$vendor_mac_arr = json_decode(file_get_contents($mac_file), true);
6011
		$mac = (is_macaddr($vendor_mac_arr[$interface])) ? $vendor_mac_arr[$interface] : '';
6012
	}
6013

    
6014
	return $mac;
6015
}
6016

    
6017
/****f* pfsense-utils/generate_random_mac_address
6018
 * NAME
6019
 *   generate_random_mac - generates a random mac address
6020
 * INPUTS
6021
 *   none
6022
 * RESULT
6023
 *   $mac - a random mac address
6024
 ******/
6025
function generate_random_mac_address() {
6026
	$mac = "02";
6027
	for ($x = 0; $x < 5; $x++) {
6028
		$mac .= ":" . dechex(rand(16, 255));
6029
	}
6030
	return $mac;
6031
}
6032

    
6033
/****f* interfaces/is_jumbo_capable
6034
 * NAME
6035
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6036
 * INPUTS
6037
 *   $int             - string containing interface name
6038
 * RESULT
6039
 *   boolean          - true or false
6040
 ******/
6041
function is_jumbo_capable($iface) {
6042
	$iface = trim($iface);
6043
	$capable = pfSense_get_interface_addresses($iface);
6044

    
6045
	if (isset($capable['caps']['vlanmtu'])) {
6046
		return true;
6047
	}
6048

    
6049
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6050
	if (substr($iface, 0, 4) == "lagg") {
6051
		return true;
6052
	}
6053

    
6054
	return false;
6055
}
6056

    
6057
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6058
	global $g;
6059

    
6060
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6061

    
6062
	if (!empty($iface) && !empty($pppif)) {
6063
		$cron_cmd = <<<EOD
6064
#!/bin/sh
6065
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6066
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6067

    
6068
EOD;
6069

    
6070
		@file_put_contents($cron_file, $cron_cmd);
6071
		chmod($cron_file, 0755);
6072
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6073
	} else {
6074
		unlink_if_exists($cron_file);
6075
	}
6076
}
6077

    
6078
function get_interface_default_mtu($type = "ethernet") {
6079
	switch ($type) {
6080
		case "gre":
6081
			return 1476;
6082
			break;
6083
		case "gif":
6084
			return 1280;
6085
			break;
6086
		case "tun":
6087
		case "vlan":
6088
		case "tap":
6089
		case "ethernet":
6090
		default:
6091
			return 1500;
6092
			break;
6093
	}
6094

    
6095
	/* Never reached */
6096
	return 1500;
6097
}
6098

    
6099
function get_vip_descr($ipaddress) {
6100
	global $config;
6101

    
6102
	foreach ($config['virtualip']['vip'] as $vip) {
6103
		if ($vip['subnet'] == $ipaddress) {
6104
			return ($vip['descr']);
6105
		}
6106
	}
6107
	return "";
6108
}
6109

    
6110
function interfaces_staticarp_configure($if) {
6111
	global $config, $g;
6112
	if (isset($config['system']['developerspew'])) {
6113
		$mt = microtime();
6114
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6115
	}
6116

    
6117
	$ifcfg = $config['interfaces'][$if];
6118

    
6119
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6120
		return 0;
6121
	}
6122

    
6123
	/* Enable staticarp, if enabled */
6124
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6125
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6126
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6127
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6128
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6129
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6130
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6131
				}
6132
			}
6133
		}
6134
	} else {
6135
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6136
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6137
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6138
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6139
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6140
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6141
				}
6142
			}
6143
		}
6144
	}
6145

    
6146
	return 0;
6147
}
6148

    
6149
function get_failover_interface($interface, $family = "all") {
6150
	global $config;
6151

    
6152
	/* shortcut to get_real_interface if we find it in the config */
6153
	if (is_array($config['interfaces'][$interface])) {
6154
		return get_real_interface($interface, $family);
6155
	}
6156

    
6157
	/* compare against gateway groups */
6158
	$a_groups = return_gateway_groups_array();
6159
	if (is_array($a_groups[$interface])) {
6160
		/* we found a gateway group, fetch the interface or vip */
6161
		if (!empty($a_groups[$interface][0]['vip'])) {
6162
			return $a_groups[$interface][0]['vip'];
6163
		} else {
6164
			return $a_groups[$interface][0]['int'];
6165
		}
6166
	}
6167
	/* fall through to get_real_interface */
6168
	/* XXX: Really needed? */
6169
	return get_real_interface($interface, $family);
6170
}
6171

    
6172
/****f* interfaces/interface_has_dhcp
6173
 * NAME
6174
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6175
 * INPUTS
6176
 *   interface or gateway group name
6177
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6178
 * RESULT
6179
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6180
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6181
 ******/
6182
function interface_has_dhcp($interface, $family = 4) {
6183
	global $config;
6184

    
6185
	if ($config['interfaces'][$interface]) {
6186
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6187
			return true;
6188
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6189
			return true;
6190
		} else {
6191
			return false;
6192
		}
6193
	}
6194

    
6195
	if (!is_array($config['gateways']['gateway_group'])) {
6196
		return false;
6197
	}
6198

    
6199
	if ($family == 6) {
6200
		$dhcp_string = "_DHCP6";
6201
	} else {
6202
		$dhcp_string = "_DHCP";
6203
	}
6204

    
6205
	foreach ($config['gateways']['gateway_group'] as $group) {
6206
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6207
			continue;
6208
		}
6209
		foreach ($group['item'] as $item) {
6210
			$item_data = explode("|", $item);
6211
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6212
				return true;
6213
			}
6214
		}
6215
	}
6216

    
6217
	return false;
6218
}
6219

    
6220
function remove_ifindex($ifname) {
6221
	return preg_replace("/[0-9]+$/", "", $ifname);
6222
}
6223

    
6224
?>
(18-18/51)