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

    
3300
	/* media */
3301
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3302
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3303
		if ($wancfg['media']) {
3304
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3305
		}
3306
		if ($wancfg['mediaopt']) {
3307
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3308
		}
3309
		mwexec($cmd);
3310
	}
3311

    
3312
	/* Apply hw offloading policies as configured */
3313
	enable_hardware_offloading($interface);
3314

    
3315
	/* invalidate interface/ip/sn cache */
3316
	get_interface_arr(true);
3317
	unset($interface_ip_arr_cache[$realif]);
3318
	unset($interface_sn_arr_cache[$realif]);
3319
	unset($interface_ipv6_arr_cache[$realif]);
3320
	unset($interface_snv6_arr_cache[$realif]);
3321

    
3322
	$tunnelif = substr($realif, 0, 3);
3323

    
3324
	$mtuif = $realif;
3325
	$mtuhwif = $realhwif;
3326

    
3327
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3328
	if (interface_isppp_type($interface)) {
3329
		$mtuif = $realhwif;
3330
		$mtuhwif_array = get_parent_interface($mtuif);
3331
		$mtuhwif = $mtuhwif_array[0];
3332
	}
3333

    
3334
	$wantedmtu = 0;
3335
	if (is_array($config['interfaces'])) {
3336
		foreach ($config['interfaces'] as $tmpinterface) {
3337
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3338
				$wantedmtu = $tmpinterface['mtu'];
3339
				break;
3340
			}
3341
		}
3342
	}
3343

    
3344
	/* MTU is not specified for interface, try the pppoe settings. */
3345
	if ($wantedmtu == 0) {
3346
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3347
	}
3348
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3349
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3350
	}
3351

    
3352
	/* Set the MTU to 1500 if no explicit MTU configured. */
3353
	if ($wantedmtu == 0) {
3354
		$wantedmtu = 1500; /* Default */
3355
	}
3356

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

    
3366
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3367

    
3368
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3369
			$configuredmtu = $parentmtu;
3370
		if ($configuredmtu != 0)
3371
			$mtu = $configuredmtu;
3372
		else
3373
			$mtu = $wantedmtu;
3374

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

    
3400
	if (does_interface_exist($wancfg['if'])) {
3401
		interfaces_bring_up($wancfg['if']);
3402
	}
3403

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

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

    
3455
	interface_netgraph_needed($interface);
3456

    
3457
	if (!platform_booting()) {
3458
		link_interface_to_vips($interface, "update");
3459

    
3460
		if ($tunnelif != 'gre') {
3461
			unset($gre);
3462
			$gre = link_interface_to_gre($interface);
3463
			if (!empty($gre)) {
3464
				array_walk($gre, 'interface_gre_configure');
3465
			}
3466
		}
3467

    
3468
		if ($tunnelif != 'gif') {
3469
			unset($gif);
3470
			$gif = link_interface_to_gif ($interface);
3471
			if (!empty($gif)) {
3472
				array_walk($gif, 'interface_gif_configure');
3473
			}
3474
		}
3475

    
3476
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3477
			unset($bridgetmp);
3478
			$bridgetmp = link_interface_to_bridge($interface);
3479
			if (!empty($bridgetmp)) {
3480
				interface_bridge_add_member($bridgetmp, $realif);
3481
			}
3482
		}
3483

    
3484
		$grouptmp = link_interface_to_group($interface);
3485
		if (!empty($grouptmp)) {
3486
			array_walk($grouptmp, 'interface_group_add_member');
3487
		}
3488

    
3489
		if ($interface == "lan") {
3490
			/* make new hosts file */
3491
			system_hosts_generate();
3492
		}
3493

    
3494
		if ($reloadall == true) {
3495

    
3496
			/* reconfigure static routes (kernel may have deleted them) */
3497
			system_routing_configure($interface);
3498

    
3499
			/* reload ipsec tunnels */
3500
			send_event("service reload ipsecdns");
3501

    
3502
			if (isset($config['dnsmasq']['enable'])) {
3503
				services_dnsmasq_configure();
3504
			}
3505

    
3506
			if (isset($config['unbound']['enable'])) {
3507
				services_unbound_configure();
3508
			}
3509

    
3510
			/* update dyndns */
3511
			send_event("service reload dyndns {$interface}");
3512

    
3513
			/* reload captive portal */
3514
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3515
				require_once('captiveportal.inc');
3516
			}
3517
			captiveportal_init_rules_byinterface($interface);
3518
		}
3519
	}
3520

    
3521
	interfaces_staticarp_configure($interface);
3522
	return 0;
3523
}
3524

    
3525
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3526
	global $config, $g;
3527

    
3528
	if (!is_array($wancfg)) {
3529
		return;
3530
	}
3531

    
3532
	if (!isset($wancfg['enable'])) {
3533
		return;
3534
	}
3535

    
3536
	/* If the interface is not configured via another, exit */
3537
	if (empty($wancfg['track6-interface'])) {
3538
		return;
3539
	}
3540

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

    
3551
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3552
	if (!isset($trackcfg['enable'])) {
3553
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3554
		return;
3555
	}
3556

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

    
3587
	if ($linkupevent == false && !platform_booting()) {
3588
		if (!function_exists('services_dhcpd_configure')) {
3589
			require_once("services.inc");
3590
		}
3591

    
3592
		/* restart dns servers (defering dhcpd reload) */
3593
		if (isset($config['unbound']['enable'])) {
3594
			services_unbound_configure(false);
3595
		}
3596
		if (isset($config['dnsmasq']['enable'])) {
3597
			services_dnsmasq_configure(false);
3598
		}
3599

    
3600
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
3601
		services_dhcpd_configure("inet6");
3602
	}
3603

    
3604
	return 0;
3605
}
3606

    
3607
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3608
	global $config, $g;
3609
	global $interface_ipv6_arr_cache;
3610
	global $interface_snv6_arr_cache;
3611

    
3612
	if (!is_array($lancfg)) {
3613
		return;
3614
	}
3615

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

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

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

    
3634
	/* create the long prefix notation for math, save the prefix length */
3635
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3636
	$rd6prefixlen = $rd6prefix[1];
3637
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3638

    
3639
	/* binary presentation of the prefix for all 128 bits. */
3640
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3641

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

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

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

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

    
3668
	return 0;
3669
}
3670

    
3671
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3672
	global $config, $g;
3673
	global $interface_ipv6_arr_cache;
3674
	global $interface_snv6_arr_cache;
3675

    
3676
	if (!is_array($lancfg)) {
3677
		return;
3678
	}
3679

    
3680
	/* If the interface is not configured via another, exit */
3681
	if (empty($lancfg['track6-interface'])) {
3682
		return;
3683
	}
3684

    
3685
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3686
	if (empty($wancfg)) {
3687
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3688
		return;
3689
	}
3690

    
3691
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3692
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3693
		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']));
3694
		return;
3695
	}
3696
	$hexwanv4 = return_hex_ipv4($ip4address);
3697

    
3698
	/* create the long prefix notation for math, save the prefix length */
3699
	$sixto4prefix = "2002::";
3700
	$sixto4prefixlen = 16;
3701
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3702

    
3703
	/* binary presentation of the prefix for all 128 bits. */
3704
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3705

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

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

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

    
3728
	return 0;
3729
}
3730

    
3731
function interface_6rd_configure($interface = "wan", $wancfg) {
3732
	global $config, $g;
3733

    
3734
	/* because this is a tunnel interface we can only function
3735
	 *	with a public IPv4 address on the interface */
3736

    
3737
	if (!is_array($wancfg)) {
3738
		return;
3739
	}
3740

    
3741
	if (!is_module_loaded('if_stf.ko')) {
3742
		mwexec('/sbin/kldload if_stf.ko');
3743
	}
3744

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

    
3753
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3754
		$wancfg['prefix-6rd-v4plen'] = 0;
3755
	}
3756

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

    
3770
	/* binary presentation of the prefix for all 128 bits. */
3771
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3772

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

    
3780
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3781
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3782

    
3783

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

    
3804
	/* write out a default router file */
3805
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3806
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3807

    
3808
	$ip4gateway = get_interface_gateway($interface);
3809
	if (is_ipaddrv4($ip4gateway)) {
3810
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
3811
	}
3812

    
3813
	/* configure dependent interfaces */
3814
	if (!platform_booting()) {
3815
		link_interface_to_track6($interface, "update");
3816
	}
3817

    
3818
	return 0;
3819
}
3820

    
3821
function interface_6to4_configure($interface = "wan", $wancfg) {
3822
	global $config, $g;
3823

    
3824
	/* because this is a tunnel interface we can only function
3825
	 *	with a public IPv4 address on the interface */
3826

    
3827
	if (!is_array($wancfg)) {
3828
		return;
3829
	}
3830

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

    
3838
	/* create the long prefix notation for math, save the prefix length */
3839
	$stfprefixlen = 16;
3840
	$stfprefix = Net_IPv6::uncompress("2002::");
3841
	$stfarr = explode(":", $stfprefix);
3842
	$v4prefixlen = "0";
3843

    
3844
	/* we need the hex form of the interface IPv4 address */
3845
	$ip4arr = explode(".", $ip4address);
3846
	$hexwanv4 = "";
3847
	foreach ($ip4arr as $octet) {
3848
		$hexwanv4 .= sprintf("%02x", $octet);
3849
	}
3850

    
3851
	/* we need the hex form of the broker IPv4 address */
3852
	$ip4arr = explode(".", "192.88.99.1");
3853
	$hexbrv4 = "";
3854
	foreach ($ip4arr as $octet) {
3855
		$hexbrv4 .= sprintf("%02x", $octet);
3856
	}
3857

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

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

    
3870
	/* for the local subnet too. */
3871
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3872
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3873

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

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

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

    
3907
	if ($g['debug']) {
3908
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3909
	}
3910

    
3911
	/* write out a default router file */
3912
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3913
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3914

    
3915
	$ip4gateway = get_interface_gateway($interface);
3916
	if (is_ipaddrv4($ip4gateway)) {
3917
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
3918
	}
3919

    
3920
	if (!platform_booting()) {
3921
		link_interface_to_track6($interface, "update");
3922
	}
3923

    
3924
	return 0;
3925
}
3926

    
3927
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3928
	global $config, $g;
3929

    
3930
	if (!is_array($wancfg)) {
3931
		return;
3932
	}
3933

    
3934
	$wanif = get_real_interface($interface, "inet6");
3935
	$dhcp6cconf = "";
3936

    
3937
	if (!empty($config['system']['global-v6duid'])) {
3938
		// Write the DUID file
3939
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
3940
		    log_error(gettext("Failed to write user DUID file!"));
3941
		}
3942
	}
3943

    
3944
	if ($wancfg['adv_dhcp6_config_file_override']) {
3945
		// DHCP6 Config File Override
3946
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3947
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3948
		// DHCP6 Config File Advanced
3949
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3950
	} else {
3951
		// DHCP6 Config File Basic
3952
		$dhcp6cconf .= "interface {$wanif} {\n";
3953

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

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

    
3978
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3979
			$dhcp6cconf .= "\trequest domain-name;\n";
3980

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

    
3992
			if (!isset($wancfg['dhcp6prefixonly'])) {
3993
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3994
			}
3995

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

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

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

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

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

    
4080
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4081
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4082

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

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

    
4135
	/* accept router advertisements for this interface */
4136
	log_error("Accept router advertisements on interface {$wanif} ");
4137
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4138

    
4139
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4140
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4141
		sleep(2);
4142
	}
4143

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

    
4183
	return 0;
4184
}
4185

    
4186
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4187
	global $g;
4188

    
4189
	$send_options = "";
4190
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4191
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4192
		foreach ($options as $option) {
4193
			$send_options .= "\tsend " . trim($option) . ";\n";
4194
		}
4195
	}
4196

    
4197
	$request_options = "";
4198
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4199
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4200
		foreach ($options as $option) {
4201
			$request_options .= "\trequest " . trim($option) . ";\n";
4202
		}
4203
	}
4204

    
4205
	$information_only = "";
4206
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4207
		$information_only = "\tinformation-only;\n";
4208
	}
4209

    
4210
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4211
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4212
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4213
	}
4214

    
4215
	$interface_statement  = "interface";
4216
	$interface_statement .= " {$wanif}";
4217
	$interface_statement .= " {\n";
4218
	$interface_statement .= "$send_options";
4219
	$interface_statement .= "$request_options";
4220
	$interface_statement .= "$information_only";
4221
	$interface_statement .= "$script";
4222
	$interface_statement .= "};\n";
4223

    
4224
	$id_assoc_statement_address = "";
4225
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4226
		$id_assoc_statement_address .= "id-assoc";
4227
		$id_assoc_statement_address .= " na";
4228
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4229
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4230
		}
4231
		$id_assoc_statement_address .= " { ";
4232

    
4233
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4234
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4235
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4236
			$id_assoc_statement_address .= "\n\taddress";
4237
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4238
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4239
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4240
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4241
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4242
			}
4243
			$id_assoc_statement_address .= ";\n";
4244
		}
4245

    
4246
		$id_assoc_statement_address .= "};\n";
4247
	}
4248

    
4249
	$id_assoc_statement_prefix = "";
4250
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4251
		$id_assoc_statement_prefix .= "id-assoc";
4252
		$id_assoc_statement_prefix .= " pd";
4253
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4254
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4255
		}
4256
		$id_assoc_statement_prefix .= " { ";
4257

    
4258
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4259
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4260
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4261
			$id_assoc_statement_prefix .= "\n\tprefix";
4262
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4263
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4264
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4265
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4266
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4267
			}
4268
			$id_assoc_statement_prefix .= ";";
4269
		}
4270

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

    
4283
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4284
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4285
			$id_assoc_statement_prefix .= "\n";
4286
		}
4287

    
4288
		$id_assoc_statement_prefix .= "};\n";
4289
	}
4290

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

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

    
4324
	$dhcp6cconf  = $interface_statement;
4325
	$dhcp6cconf .= $id_assoc_statement_address;
4326
	$dhcp6cconf .= $id_assoc_statement_prefix;
4327
	$dhcp6cconf .= $authentication_statement;
4328
	$dhcp6cconf .= $key_info_statement;
4329

    
4330
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4331

    
4332
	return $dhcp6cconf;
4333
}
4334

    
4335

    
4336
function DHCP6_Config_File_Override($wancfg, $wanif) {
4337

    
4338
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4339

    
4340
	if ($dhcp6cconf === false) {
4341
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4342
		return '';
4343
	} else {
4344
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4345
	}
4346
}
4347

    
4348

    
4349
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4350

    
4351
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4352

    
4353
	return $dhcp6cconf;
4354
}
4355

    
4356

    
4357
function interface_dhcp_configure($interface = "wan") {
4358
	global $config, $g;
4359

    
4360
	$wancfg = $config['interfaces'][$interface];
4361
	$wanif = $wancfg['if'];
4362
	if (empty($wancfg)) {
4363
		$wancfg = array();
4364
	}
4365

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

    
4373
	if ($wancfg['dhcphostname']) {
4374
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4375
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4376
	} else {
4377
		$dhclientconf_hostname = "";
4378
	}
4379

    
4380
	$wanif = get_real_interface($interface);
4381
	if (empty($wanif)) {
4382
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4383
		return 0;
4384
	}
4385
	$dhclientconf = "";
4386

    
4387
	$dhclientconf .= <<<EOD
4388
interface "{$wanif}" {
4389
timeout 60;
4390
retry 15;
4391
select-timeout 0;
4392
initial-interval 1;
4393
	{$dhclientconf_hostname}
4394
	script "/usr/local/sbin/pfSense-dhclient-script";
4395
EOD;
4396

    
4397
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4398
		$dhclientconf .= <<<EOD
4399

    
4400
	reject {$wancfg['dhcprejectfrom']};
4401
EOD;
4402
	}
4403
	$dhclientconf .= <<<EOD
4404

    
4405
}
4406

    
4407
EOD;
4408

    
4409
	// DHCP Config File Advanced
4410
	if ($wancfg['adv_dhcp_config_advanced']) {
4411
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4412
	}
4413

    
4414
	if (is_ipaddr($wancfg['alias-address'])) {
4415
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4416
		$dhclientconf .= <<<EOD
4417
alias {
4418
	interface "{$wanif}";
4419
	fixed-address {$wancfg['alias-address']};
4420
	option subnet-mask {$subnetmask};
4421
}
4422

    
4423
EOD;
4424
	}
4425

    
4426
	// DHCP Config File Override
4427
	if ($wancfg['adv_dhcp_config_file_override']) {
4428
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4429
	}
4430

    
4431
	fwrite($fd, $dhclientconf);
4432
	fclose($fd);
4433

    
4434
	/* bring wan interface up before starting dhclient */
4435
	if ($wanif) {
4436
		interfaces_bring_up($wanif);
4437
	} else {
4438
		log_error(sprintf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4439
	}
4440

    
4441
	/* Make sure dhclient is not running */
4442
	kill_dhclient_process($wanif);
4443

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

    
4447
	return 0;
4448
}
4449

    
4450
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4451

    
4452
	$hostname = "";
4453
	if ($wancfg['dhcphostname'] != '') {
4454
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4455
	}
4456

    
4457
	/* DHCP Protocol Timings */
4458
	$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");
4459
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4460
		$pt_variable = "{$Protocol_Timing}";
4461
		${$pt_variable} = "";
4462
		if ($wancfg[$Protocol_Timing] != "") {
4463
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4464
		}
4465
	}
4466

    
4467
	$send_options = "";
4468
	if ($wancfg['adv_dhcp_send_options'] != '') {
4469
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4470
		foreach ($options as $option) {
4471
			$send_options .= "\tsend " . trim($option) . ";\n";
4472
		}
4473
	}
4474

    
4475
	$request_options = "";
4476
	if ($wancfg['adv_dhcp_request_options'] != '') {
4477
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4478
	}
4479

    
4480
	$required_options = "";
4481
	if ($wancfg['adv_dhcp_required_options'] != '') {
4482
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4483
	}
4484

    
4485
	$option_modifiers = "";
4486
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4487
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4488
		foreach ($modifiers as $modifier) {
4489
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4490
		}
4491
	}
4492

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

    
4516
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4517

    
4518
	return $dhclientconf;
4519
}
4520

    
4521
function DHCP_Config_Option_Split($option_string) {
4522
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4523
	return $matches ? $matches[0] : [];
4524
}
4525

    
4526
function DHCP_Config_File_Override($wancfg, $wanif) {
4527

    
4528
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4529

    
4530
	if ($dhclientconf === false) {
4531
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $wancfg['adv_dhcp_config_file_override_path']));
4532
		return '';
4533
	} else {
4534
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4535
	}
4536
}
4537

    
4538

    
4539
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4540

    
4541
	/* Apply Interface Substitutions */
4542
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4543

    
4544
	/* Apply Hostname Substitutions */
4545
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4546

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

    
4553
	/* Apply MAC Address Substitutions */
4554
	foreach ($various_mac_types as $various_mac_type) {
4555
		foreach ($various_mac_cases as $various_mac_case) {
4556
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4557

    
4558
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4559
				if ($res !== false) {
4560

    
4561
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4562
					if ("$various_mac_case" == "U") {
4563
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4564
					}
4565
					if ("$various_mac_case" == "L") {
4566
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4567
					}
4568

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

    
4581
					/* MAC Address Delimiter Substitutions */
4582
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4583

    
4584
					/* Apply MAC Address Substitutions */
4585
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4586
				}
4587
			}
4588
		}
4589
	}
4590

    
4591
	return $dhclientconf;
4592
}
4593

    
4594
function interfaces_group_setup() {
4595
	global $config;
4596

    
4597
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4598
		return;
4599
	}
4600

    
4601
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4602
		interface_group_setup($groupar);
4603
	}
4604

    
4605
	return;
4606
}
4607

    
4608
function interface_group_setup(&$groupname /* The parameter is an array */) {
4609
	global $config;
4610

    
4611
	if (!is_array($groupname)) {
4612
		return;
4613
	}
4614
	$members = explode(" ", $groupname['members']);
4615
	foreach ($members as $ifs) {
4616
		$realif = get_real_interface($ifs);
4617
		if ($realif && does_interface_exist($realif)) {
4618
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4619
		}
4620
	}
4621

    
4622
	return;
4623
}
4624

    
4625
function is_interface_group($if) {
4626
	global $config;
4627

    
4628
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4629
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4630
			if ($groupentry['ifname'] === $if) {
4631
				return true;
4632
			}
4633
		}
4634
	}
4635

    
4636
	return false;
4637
}
4638

    
4639
function interface_group_add_member($interface, $groupname) {
4640
	$interface = get_real_interface($interface);
4641
	if (does_interface_exist($interface)) {
4642
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4643
	}
4644
}
4645

    
4646
/* COMPAT Function */
4647
function convert_friendly_interface_to_real_interface_name($interface) {
4648
	return get_real_interface($interface);
4649
}
4650

    
4651
/* COMPAT Function */
4652
function get_real_wan_interface($interface = "wan") {
4653
	return get_real_interface($interface);
4654
}
4655

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

    
4661
/*
4662
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4663
 */
4664
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4665
	global $config;
4666

    
4667
	/* XXX: For speed reasons reference directly the interface array */
4668
	$ifdescrs = &$config['interfaces'];
4669
	//$ifdescrs = get_configured_interface_list(false, true);
4670

    
4671
	foreach ($ifdescrs as $if => $ifname) {
4672
		if ($if == $interface || $ifname['if'] == $interface) {
4673
			return $if;
4674
		}
4675

    
4676
		if (get_real_interface($if) == $interface) {
4677
			return $if;
4678
		}
4679

    
4680
		if ($checkparent == false) {
4681
			continue;
4682
		}
4683

    
4684
		$int = get_parent_interface($if, true);
4685
		if (is_array($int)) {
4686
			foreach ($int as $iface) {
4687
				if ($iface == $interface) {
4688
					return $if;
4689
				}
4690
			}
4691
		}
4692
	}
4693

    
4694
	if ($interface == "enc0") {
4695
		return 'IPsec';
4696
	}
4697
}
4698

    
4699
/* attempt to resolve interface to friendly descr */
4700
function convert_friendly_interface_to_friendly_descr($interface) {
4701
	global $config;
4702

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

    
4756
	return $ifdesc;
4757
}
4758

    
4759
function convert_real_interface_to_friendly_descr($interface) {
4760

    
4761
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4762

    
4763
	if (!empty($ifdesc)) {
4764
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4765
	}
4766

    
4767
	return $interface;
4768
}
4769

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

    
4782
	$parents = array();
4783
	//Check that we got a valid interface passed
4784
	$realif = get_real_interface($interface);
4785
	if ($realif == NULL) {
4786
		return $parents;
4787
	}
4788

    
4789
	// If we got a real interface, find it's friendly assigned name
4790
	if ($interface == $realif && $avoidrecurse == false) {
4791
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4792
	}
4793

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

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

    
4847
	if (empty($parents)) {
4848
		$parents[0] = $realif;
4849
	}
4850

    
4851
	return $parents;
4852
}
4853

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

    
4862
	$realif = get_parent_interface($interface);
4863

    
4864
	if (substr($realif[0], 0, 4) == "lagg") {
4865
		foreach ($config['laggs']['lagg'] as $lagg) {
4866
			if ($realif[0] == $lagg['laggif']) {
4867
				return explode(",", $lagg['members']);
4868
			}
4869
		}
4870
	} else {
4871
		return $realif;
4872
	}
4873
}
4874

    
4875
function interface_is_wireless_clone($wlif) {
4876
	if (!stristr($wlif, "_wlan")) {
4877
		return false;
4878
	} else {
4879
		return true;
4880
	}
4881
}
4882

    
4883
function interface_get_wireless_base($wlif) {
4884
	if (!stristr($wlif, "_wlan")) {
4885
		return $wlif;
4886
	} else {
4887
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4888
	}
4889
}
4890

    
4891
function interface_get_wireless_clone($wlif) {
4892
	if (!stristr($wlif, "_wlan")) {
4893
		return $wlif . "_wlan0";
4894
	} else {
4895
		return $wlif;
4896
	}
4897
}
4898

    
4899
function interface_list_wireless() {
4900
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
4901

    
4902
	$result = array();
4903
	foreach ($portlist as $port) {
4904
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
4905
			continue;
4906
		}
4907

    
4908
		$desc = $port . " ( " . get_single_sysctl(
4909
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
4910

    
4911
		$result[] = array(
4912
		    "if" => $port,
4913
		    "descr" => $desc
4914
		);
4915
	}
4916

    
4917
	return $result;
4918
}
4919

    
4920
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4921
	global $config, $g;
4922

    
4923
	$wanif = NULL;
4924

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

    
4967
			if (empty($config['interfaces'][$interface])) {
4968
				break;
4969
			}
4970

    
4971
			$cfg = &$config['interfaces'][$interface];
4972

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

    
5029
	return $wanif;
5030
}
5031

    
5032
/* Guess the physical interface by providing a IP address */
5033
function guess_interface_from_ip($ipaddress) {
5034

    
5035
	$family = '';
5036
	if (is_ipaddrv4($ipaddress)) {
5037
		$family = 'inet';
5038
	}
5039
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5040
		$family = 'inet6';
5041
	}
5042

    
5043
	if (empty($family)) {
5044
		return false;
5045
	}
5046

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

    
5055
	return false;
5056
}
5057

    
5058
/*
5059
 * find_ip_interface($ip): return the interface where an ip is defined
5060
 *   (or if $bits is specified, where an IP within the subnet is defined)
5061
 */
5062
function find_ip_interface($ip, $bits = null) {
5063
	if (!is_ipaddr($ip)) {
5064
		return false;
5065
	}
5066

    
5067
	$isv6ip = is_ipaddrv6($ip);
5068

    
5069
	/* if list */
5070
	$ifdescrs = get_configured_interface_list();
5071

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

    
5090
	return false;
5091
}
5092

    
5093
/*
5094
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5095
 *   (or if $bits is specified, where an IP within the subnet is found)
5096
 */
5097
function find_virtual_ip_alias($ip, $bits = null) {
5098
	global $config;
5099

    
5100
	if (!is_array($config['virtualip']['vip'])) {
5101
		return false;
5102
	}
5103
	if (!is_ipaddr($ip)) {
5104
		return false;
5105
	}
5106

    
5107
	$isv6ip = is_ipaddrv6($ip);
5108

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

    
5129
function link_interface_to_track6($int, $action = "") {
5130
	global $config;
5131

    
5132
	if (empty($int)) {
5133
		return;
5134
	}
5135

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

    
5154
function interface_find_child_cfgmtu($realiface) {
5155
	global $config;
5156

    
5157
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5158
	$vlans = link_interface_to_vlans($realiface);
5159
	$qinqs = link_interface_to_qinqs($realiface);
5160
	$bridge = link_interface_to_bridge($realiface);
5161
	if (!empty($interface)) {
5162
		$gifs = link_interface_to_gif($interface);
5163
		$gres = link_interface_to_gre($interface);
5164
	} else {
5165
		$gifs = array();
5166
		$gres = array();
5167
	}
5168

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

    
5230
	return $mtu;
5231
}
5232

    
5233
function link_interface_to_vlans($int, $action = "") {
5234
	global $config;
5235

    
5236
	if (empty($int)) {
5237
		return;
5238
	}
5239

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

    
5257
function link_interface_to_qinqs($int, $action = "") {
5258
	global $config;
5259

    
5260
	if (empty($int)) {
5261
		return;
5262
	}
5263

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

    
5281
function link_interface_to_vips($int, $action = "", $vhid = '') {
5282
	global $config;
5283

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

    
5311
	return NULL;
5312
}
5313

    
5314
/****f* interfaces/link_interface_to_bridge
5315
 * NAME
5316
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5317
 * INPUTS
5318
 *   $ip
5319
 * RESULT
5320
 *   bridge[0-99]
5321
 ******/
5322
function link_interface_to_bridge($int) {
5323
	global $config;
5324

    
5325
	if (is_array($config['bridges']['bridged'])) {
5326
		foreach ($config['bridges']['bridged'] as $bridge) {
5327
			if (in_array($int, explode(',', $bridge['members']))) {
5328
				return "{$bridge['bridgeif']}";
5329
			}
5330
		}
5331
	}
5332
}
5333

    
5334
function link_interface_to_group($int) {
5335
	global $config;
5336

    
5337
	$result = array();
5338

    
5339
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5340
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5341
			if (in_array($int, explode(" ", $group['members']))) {
5342
				$result[$group['ifname']] = $int;
5343
			}
5344
		}
5345
	}
5346

    
5347
	return $result;
5348
}
5349

    
5350
function link_interface_to_gre($interface) {
5351
	global $config;
5352

    
5353
	$result = array();
5354

    
5355
	if (is_array($config['gres']['gre'])) {
5356
		foreach ($config['gres']['gre'] as $gre) {
5357
			if ($gre['if'] == $interface) {
5358
				$result[] = $gre;
5359
			}
5360
		}
5361
	}
5362

    
5363
	return $result;
5364
}
5365

    
5366
function link_interface_to_gif($interface) {
5367
	global $config;
5368

    
5369
	$result = array();
5370

    
5371
	if (is_array($config['gifs']['gif'])) {
5372
		foreach ($config['gifs']['gif'] as $gif) {
5373
			if ($gif['if'] == $interface) {
5374
				$result[] = $gif;
5375
			}
5376
		}
5377
	}
5378

    
5379
	return $result;
5380
}
5381

    
5382
/*
5383
 * find_interface_ip($interface): return the interface ip (first found)
5384
 */
5385
function find_interface_ip($interface, $flush = false) {
5386
	global $interface_ip_arr_cache;
5387
	global $interface_sn_arr_cache;
5388

    
5389
	$interface = str_replace("\n", "", $interface);
5390

    
5391
	if (!does_interface_exist($interface)) {
5392
		return;
5393
	}
5394

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

    
5416
	return $interface_ip_arr_cache[$interface];
5417
}
5418

    
5419
/*
5420
 * find_interface_ipv6($interface): return the interface ip (first found)
5421
 */
5422
function find_interface_ipv6($interface, $flush = false) {
5423
	global $interface_ipv6_arr_cache;
5424
	global $interface_snv6_arr_cache;
5425
	global $config;
5426

    
5427
	$interface = trim($interface);
5428
	$interface = get_real_interface($interface);
5429

    
5430
	if (!does_interface_exist($interface)) {
5431
		return;
5432
	}
5433

    
5434
	/* Setup IP cache */
5435
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5436
		$ifinfo = pfSense_get_interface_addresses($interface);
5437
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5438
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5439
	}
5440

    
5441
	return $interface_ipv6_arr_cache[$interface];
5442
}
5443

    
5444
/*
5445
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5446
 */
5447
function find_interface_ipv6_ll($interface, $flush = false) {
5448
	global $interface_llv6_arr_cache;
5449
	global $config;
5450

    
5451
	$interface = str_replace("\n", "", $interface);
5452

    
5453
	if (!does_interface_exist($interface)) {
5454
		return;
5455
	}
5456

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

    
5473
function find_interface_subnet($interface, $flush = false) {
5474
	global $interface_sn_arr_cache;
5475
	global $interface_ip_arr_cache;
5476

    
5477
	$interface = str_replace("\n", "", $interface);
5478
	if (does_interface_exist($interface) == false) {
5479
		return;
5480
	}
5481

    
5482
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5483
		$ifinfo = pfSense_get_interface_addresses($interface);
5484
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5485
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5486
	}
5487

    
5488
	return $interface_sn_arr_cache[$interface];
5489
}
5490

    
5491
function find_interface_subnetv6($interface, $flush = false) {
5492
	global $interface_snv6_arr_cache;
5493
	global $interface_ipv6_arr_cache;
5494

    
5495
	$interface = str_replace("\n", "", $interface);
5496
	if (does_interface_exist($interface) == false) {
5497
		return;
5498
	}
5499

    
5500
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5501
		$ifinfo = pfSense_get_interface_addresses($interface);
5502
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5503
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5504
	}
5505

    
5506
	return $interface_snv6_arr_cache[$interface];
5507
}
5508

    
5509
function ip_in_interface_alias_subnet($interface, $ipalias) {
5510
	global $config;
5511

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

    
5531
	return false;
5532
}
5533

    
5534
function get_possible_listen_ips($include_ipv6_link_local=false) {
5535

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

    
5557
	$interfaces['lo0'] = 'Localhost';
5558

    
5559
	return $interfaces;
5560
}
5561

    
5562
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5563
	global $config;
5564

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

    
5579
function get_interface_ip($interface = "wan") {
5580

    
5581
	if (substr($interface, 0, 4) == '_vip') {
5582
		return get_configured_vip_ipv4($interface);
5583
	} else if (substr($interface, 0, 5) == '_lloc') {
5584
		/* No link-local address for v4. */
5585
		return null;
5586
	}
5587

    
5588
	$realif = get_failover_interface($interface, 'inet');
5589
	if (!$realif) {
5590
		return null;
5591
	}
5592

    
5593
	if (substr($realif, 0, 4) == '_vip') {
5594
		return get_configured_vip_ipv4($realif);
5595
	} else if (substr($realif, 0, 5) == '_lloc') {
5596
		/* No link-local address for v4. */
5597
		return null;
5598
	}
5599

    
5600
	if (is_array($config['interfaces'][$interface]) &&
5601
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5602
		return ($config['interfaces'][$interface]['ipaddr']);
5603
	}
5604

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

    
5618
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5619
	global $config;
5620

    
5621
	if (substr($interface, 0, 4) == '_vip') {
5622
		return get_configured_vip_ipv6($interface);
5623
	} else if (substr($interface, 0, 5) == '_lloc') {
5624
		return get_interface_linklocal($interface);
5625
	}
5626

    
5627
	$realif = get_failover_interface($interface, 'inet6');
5628
	if (!$realif) {
5629
		return null;
5630
	}
5631

    
5632
	if (substr($realif, 0, 4) == '_vip') {
5633
		return get_configured_vip_ipv6($realif);
5634
	} else if (substr($realif, 0, 5) == '_lloc') {
5635
		return get_interface_linklocal($realif);
5636
	}
5637

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

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

    
5677
function get_interface_linklocal($interface = "wan") {
5678

    
5679
	$realif = get_failover_interface($interface, 'inet6');
5680
	if (!$realif) {
5681
		return null;
5682
	}
5683

    
5684
	if (substr($interface, 0, 4) == '_vip') {
5685
		$realif = get_real_interface($interface);
5686
	} else if (substr($interface, 0, 5) == '_lloc') {
5687
		$realif = get_real_interface(substr($interface, 5));
5688
	}
5689

    
5690
	$curip = find_interface_ipv6_ll($realif);
5691
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5692
		return $curip;
5693
	} else {
5694
		return null;
5695
	}
5696
}
5697

    
5698
function get_interface_subnet($interface = "wan") {
5699

    
5700
	if (substr($interface, 0, 4) == '_vip') {
5701
		return (get_configured_vip_subnetv4($interface));
5702
	}
5703

    
5704
	$realif = get_real_interface($interface);
5705
	if (!$realif) {
5706
		return (NULL);
5707
	}
5708

    
5709
	$cursn = find_interface_subnet($realif);
5710
	if (!empty($cursn)) {
5711
		return ($cursn);
5712
	}
5713

    
5714
	return (NULL);
5715
}
5716

    
5717
function get_interface_subnetv6($interface = "wan") {
5718

    
5719
	if (substr($interface, 0, 4) == '_vip') {
5720
		return (get_configured_vip_subnetv6($interface));
5721
	} else if (substr($interface, 0, 5) == '_lloc') {
5722
		$interface = substr($interface, 5);
5723
	}
5724

    
5725
	$realif = get_real_interface($interface, 'inet6');
5726
	if (!$realif) {
5727
		return (NULL);
5728
	}
5729

    
5730
	$cursn = find_interface_subnetv6($realif);
5731
	if (!empty($cursn)) {
5732
		return ($cursn);
5733
	}
5734

    
5735
	return (NULL);
5736
}
5737

    
5738
/* return outside interfaces with a gateway */
5739
function get_interfaces_with_gateway() {
5740
	global $config;
5741

    
5742
	$ints = array();
5743

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

    
5765
/* return true if interface has a gateway */
5766
function interface_has_gateway($friendly) {
5767
	global $config;
5768

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

    
5796
	return false;
5797
}
5798

    
5799
/* return true if interface has a gateway */
5800
function interface_has_gatewayv6($friendly) {
5801
	global $config;
5802

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

    
5829
	return false;
5830
}
5831

    
5832
/****f* interfaces/is_altq_capable
5833
 * NAME
5834
 *   is_altq_capable - Test if interface is capable of using ALTQ
5835
 * INPUTS
5836
 *   $int            - string containing interface name
5837
 * RESULT
5838
 *   boolean         - true or false
5839
 ******/
5840

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

    
5855
	$int_family = remove_ifindex($int);
5856

    
5857
	if (in_array($int_family, $capable)) {
5858
		return true;
5859
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5860
		return true;
5861
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5862
		return true;
5863
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5864
		return true;
5865
	} else {
5866
		return false;
5867
	}
5868
}
5869

    
5870
/****f* interfaces/is_interface_wireless
5871
 * NAME
5872
 *   is_interface_wireless - Returns if an interface is wireless
5873
 * RESULT
5874
 *   $tmp       - Returns if an interface is wireless
5875
 ******/
5876
function is_interface_wireless($interface) {
5877
	global $config, $g;
5878

    
5879
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5880
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5881
		if (preg_match($g['wireless_regex'], $interface)) {
5882
			if (isset($config['interfaces'][$friendly])) {
5883
				$config['interfaces'][$friendly]['wireless'] = array();
5884
			}
5885
			return true;
5886
		}
5887
		return false;
5888
	} else {
5889
		return true;
5890
	}
5891
}
5892

    
5893
function get_wireless_modes($interface) {
5894
	/* return wireless modes and channels */
5895
	$wireless_modes = array();
5896

    
5897
	$cloned_interface = get_real_interface($interface);
5898

    
5899
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5900
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5901
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5902
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5903

    
5904
		$interface_channels = "";
5905
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5906
		$interface_channel_count = count($interface_channels);
5907

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

    
5941
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5942
function get_wireless_channel_info($interface) {
5943
	$wireless_channels = array();
5944

    
5945
	$cloned_interface = get_real_interface($interface);
5946

    
5947
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5948
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5949
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5950
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5951

    
5952
		$interface_channels = "";
5953
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5954

    
5955
		foreach ($interface_channels as $channel_line) {
5956
			$channel_line = explode(",", $channel_line);
5957
			if (!isset($wireless_channels[$channel_line[0]])) {
5958
				$wireless_channels[$channel_line[0]] = $channel_line;
5959
			}
5960
		}
5961
	}
5962
	return($wireless_channels);
5963
}
5964

    
5965
function set_interface_mtu($interface, $mtu) {
5966

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

    
5983
/****f* interfaces/get_interface_mtu
5984
 * NAME
5985
 *   get_interface_mtu - Return the mtu of an interface
5986
 * RESULT
5987
 *   $tmp       - Returns the mtu of an interface
5988
 ******/
5989
function get_interface_mtu($interface) {
5990
	$mtu = pfSense_interface_getmtu($interface);
5991
	return $mtu['mtu'];
5992
}
5993

    
5994
function get_interface_mac($interface) {
5995
	$macinfo = pfSense_get_interface_addresses($interface);
5996
	return $macinfo["macaddr"];
5997
}
5998

    
5999
function get_interface_vendor_mac($interface) {
6000
	global $g;
6001

    
6002
	$mac = "";
6003
	$mac_file = "{$g['cf_conf_path']}/vendor_mac_{$interface}";
6004
	if (file_exists($mac_file)) {
6005
		$mac = file_get_contents($mac_file);
6006
		if (!is_macaddr($mac)) {
6007
			$mac = "";
6008
		}
6009
	}
6010

    
6011
	return $mac;
6012
}
6013

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

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

    
6042
	if (isset($capable['caps']['vlanmtu'])) {
6043
		return true;
6044
	}
6045

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

    
6051
	return false;
6052
}
6053

    
6054
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6055
	global $g;
6056

    
6057
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6058

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

    
6065
EOD;
6066

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

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

    
6092
	/* Never reached */
6093
	return 1500;
6094
}
6095

    
6096
function get_vip_descr($ipaddress) {
6097
	global $config;
6098

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

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

    
6114
	$ifcfg = $config['interfaces'][$if];
6115

    
6116
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6117
		return 0;
6118
	}
6119

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

    
6143
	return 0;
6144
}
6145

    
6146
function get_failover_interface($interface, $family = "all") {
6147
	global $config;
6148

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

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

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

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

    
6192
	if (!is_array($config['gateways']['gateway_group'])) {
6193
		return false;
6194
	}
6195

    
6196
	if ($family == 6) {
6197
		$dhcp_string = "_DHCP6";
6198
	} else {
6199
		$dhcp_string = "_DHCP";
6200
	}
6201

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

    
6214
	return false;
6215
}
6216

    
6217
function remove_ifindex($ifname) {
6218
	return preg_replace("/[0-9]+$/", "", $ifname);
6219
}
6220

    
6221
?>
(18-18/51)