Project

General

Profile

Download (172 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Electric Sheep Fencing, LLC
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
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
1010
	}
1011
	if (is_ipaddrv6($realifgw)) {
1012
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($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
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1162
		services_dhcpd_configure();
1163

    
1164
		if (isset($config['dnsmasq']['enable'])) {
1165
			services_dnsmasq_configure();
1166
		}
1167

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

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

    
1373
	$old_router = '';
1374
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1375
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1376
	}
1377

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

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

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

    
1400
	return;
1401
}
1402

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

    
1413
	$viparr = &$config['virtualip']['vip'];
1414
	foreach ($viparr as $vip) {
1415
		if ($vip['mode'] == "carp") {
1416
			interface_carp_configure($vip);
1417
		}
1418
	}
1419
}
1420

    
1421
function interface_isppp_type($interface) {
1422
	global $config;
1423

    
1424
	if (!is_array($config['interfaces'][$interface])) {
1425
		return false;
1426
	}
1427

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

    
1441
function interfaces_ptpid_used($ptpid) {
1442
	global $config;
1443

    
1444
	if (is_array($config['ppps']['ppp'])) {
1445
		foreach ($config['ppps']['ppp'] as & $settings) {
1446
			if ($ptpid == $settings['ptpid']) {
1447
				return true;
1448
			}
1449
		}
1450
	}
1451

    
1452
	return false;
1453
}
1454

    
1455
function interfaces_ptpid_next() {
1456

    
1457
	$ptpid = 0;
1458
	while (interfaces_ptpid_used($ptpid)) {
1459
		$ptpid++;
1460
	}
1461

    
1462
	return $ptpid;
1463
}
1464

    
1465
function getMPDCRONSettings($pppif) {
1466
	global $config;
1467

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

    
1477
	return NULL;
1478
}
1479

    
1480
function handle_pppoe_reset($post_array) {
1481
	global $config, $g;
1482

    
1483
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1484
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1485

    
1486
	if (!is_array($config['cron']['item'])) {
1487
		$config['cron']['item'] = array();
1488
	}
1489

    
1490
	$itemhash = getMPDCRONSettings($pppif);
1491

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1781
EOD;
1782

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

    
1787
EOD;
1788
	}
1789

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

    
1798
EOD;
1799

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

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

    
1810
EOD;
1811
	}
1812

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

    
1818
EOD;
1819
	}
1820

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

    
1825
EOD;
1826
	}
1827

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

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

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

    
1843
EOD;
1844
		}
1845

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

    
1850
EOD;
1851
		}
1852

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

    
1857
EOD;
1858
		}
1859

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

    
1865
EOD;
1866

    
1867

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

    
1872
EOD;
1873
		}
1874

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

    
1888
EOD;
1889
		}
1890

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

    
1895
EOD;
1896
		}
1897

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

    
1902
EOD;
1903
		}
1904

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

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

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

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

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

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

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

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

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

    
1969
EOD;
1970
		}
1971

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

    
1977
EOD;
1978
		}
1979

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

    
1983

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

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

    
2014
	/* clean up old lock files */
2015
	foreach ($ports as $port) {
2016
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2017
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2018
		}
2019
	}
2020

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

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

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

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

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

    
2094
	return 1;
2095
}
2096

    
2097
function interfaces_sync_setup() {
2098
	global $g, $config;
2099

    
2100
	if (isset($config['system']['developerspew'])) {
2101
		$mt = microtime();
2102
		echo "interfaces_sync_setup() being called $mt\n";
2103
	}
2104

    
2105
	if (platform_booting()) {
2106
		echo gettext("Configuring CARP settings...");
2107
		mute_kernel_msgs();
2108
	}
2109

    
2110
	/* suck in configuration items */
2111
	if ($config['hasync']) {
2112
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2113
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2114
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2115
	} else {
2116
		unset($pfsyncinterface);
2117
		unset($pfsyncenabled);
2118
	}
2119

    
2120
	set_sysctl(array(
2121
		"net.inet.carp.preempt" => "1",
2122
		"net.inet.carp.log" => "1")
2123
	);
2124

    
2125
	if (!empty($pfsyncinterface)) {
2126
		$carp_sync_int = get_real_interface($pfsyncinterface);
2127
	} else {
2128
		unset($carp_sync_int);
2129
	}
2130

    
2131
	/* setup pfsync interface */
2132
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2133
		if (is_ipaddr($pfsyncpeerip)) {
2134
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2135
		} else {
2136
			$syncpeer = "-syncpeer";
2137
		}
2138

    
2139
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2140
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2141

    
2142
		sleep(1);
2143

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

    
2159
	$carplist = get_configured_vip_list('all', VIP_CARP);
2160
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2161
		set_single_sysctl("net.inet.carp.allow", "1");
2162
	} else {
2163
		set_single_sysctl("net.inet.carp.allow", "0");
2164
	}
2165

    
2166
	if (platform_booting()) {
2167
		unmute_kernel_msgs();
2168
		echo gettext("done.") . "\n";
2169
	}
2170
}
2171

    
2172
function interface_proxyarp_configure($interface = "") {
2173
	global $config, $g;
2174
	if (isset($config['system']['developerspew'])) {
2175
		$mt = microtime();
2176
		echo "interface_proxyarp_configure() being called $mt\n";
2177
	}
2178

    
2179
	/* kill any running choparp */
2180
	if (empty($interface)) {
2181
		killbyname("choparp");
2182
	} else {
2183
		$vipif = get_real_interface($interface);
2184
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2185
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2186
		}
2187
	}
2188

    
2189
	$paa = array();
2190
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2191

    
2192
		/* group by interface */
2193
		foreach ($config['virtualip']['vip'] as $vipent) {
2194
			if ($vipent['mode'] === "proxyarp") {
2195
				if ($vipent['interface']) {
2196
					$proxyif = $vipent['interface'];
2197
				} else {
2198
					$proxyif = "wan";
2199
				}
2200

    
2201
				if (!empty($interface) && $interface != $proxyif) {
2202
					continue;
2203
				}
2204

    
2205
				if (!is_array($paa[$proxyif])) {
2206
					$paa[$proxyif] = array();
2207
				}
2208

    
2209
				$paa[$proxyif][] = $vipent;
2210
			}
2211
		}
2212
	}
2213

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

    
2249
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2250
	global $g, $config;
2251

    
2252
	if (is_array($config['virtualip']['vip'])) {
2253
		foreach ($config['virtualip']['vip'] as $vip) {
2254

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

    
2271
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2272
				interface_vip_bring_down($vip);
2273
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2274
				interface_vip_bring_down($vip);
2275
			else if ($inet == "all")
2276
				interface_vip_bring_down($vip);
2277
		}
2278
	}
2279
}
2280

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

    
2329
function interface_ipalias_configure(&$vip) {
2330
	global $config;
2331

    
2332
	if ($vip['mode'] != 'ipalias') {
2333
		return;
2334
	}
2335

    
2336
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2337
	if ($realif != "lo0") {
2338
		$if = convert_real_interface_to_friendly_interface_name($realif);
2339
		if (!isset($config['interfaces'][$if])) {
2340
			return;
2341
		}
2342

    
2343
		if (!isset($config['interfaces'][$if]['enable'])) {
2344
			return;
2345
		}
2346
	}
2347

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

    
2363
function interface_carp_configure(&$vip) {
2364
	global $config, $g;
2365
	if (isset($config['system']['developerspew'])) {
2366
		$mt = microtime();
2367
		echo "interface_carp_configure() being called $mt\n";
2368
	}
2369

    
2370
	if ($vip['mode'] != "carp") {
2371
		return;
2372
	}
2373

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

    
2381
	$vip_password = $vip['password'];
2382
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2383
	if ($vip['password'] != "") {
2384
		$password = " pass {$vip_password}";
2385
	}
2386

    
2387
	$advbase = "";
2388
	if (!empty($vip['advbase'])) {
2389
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2390
	}
2391

    
2392
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2393
	if ($carp_maintenancemode) {
2394
		$advskew = "advskew 254";
2395
	} else {
2396
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2397
	}
2398

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

    
2401
	if (is_ipaddrv4($vip['subnet'])) {
2402
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2403
	} else if (is_ipaddrv6($vip['subnet'])) {
2404
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2405
	}
2406

    
2407
	return $realif;
2408
}
2409

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

    
2452
	if ($needs_clone == true) {
2453
		/* remove previous instance if it exists */
2454
		if (does_interface_exist($realif)) {
2455
			pfSense_interface_destroy($realif);
2456
		}
2457

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

    
2474
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2475
	global $config, $g;
2476

    
2477
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2478
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2479
				 'regdomain', 'regcountry', 'reglocation');
2480

    
2481
	if (!is_interface_wireless($ifcfg['if'])) {
2482
		return;
2483
	}
2484

    
2485
	$baseif = interface_get_wireless_base($ifcfg['if']);
2486

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

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

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

    
2549
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2550
	global $config, $g;
2551

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

    
2559
	// Remove script file
2560
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2561

    
2562
	// Clone wireless nic if needed.
2563
	interface_wireless_clone($if, $wl);
2564

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

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

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

    
2574
	/* set values for /path/program */
2575
	$hostapd = "/usr/sbin/hostapd";
2576
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2577
	$ifconfig = "/sbin/ifconfig";
2578
	$sysctl = "/sbin/sysctl";
2579
	$killall = "/usr/bin/killall";
2580

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

    
2583
	$wlcmd = array();
2584
	$wl_sysctl = array();
2585
	/* Make sure it's up */
2586
	$wlcmd[] = "up";
2587
	/* Set a/b/g standard */
2588
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2589
	/* skip mode entirely for "auto" */
2590
	if ($wlcfg['standard'] != "auto") {
2591
		$wlcmd[] = "mode " . escapeshellarg($standard);
2592
	}
2593

    
2594
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2595
	 * to prevent massive packet loss under certain conditions. */
2596
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2597
		$wlcmd[] = "-ampdu";
2598
	}
2599

    
2600
	/* Set ssid */
2601
	if ($wlcfg['ssid']) {
2602
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2603
	}
2604

    
2605
	/* Set 802.11g protection mode */
2606
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2607

    
2608
	/* set wireless channel value */
2609
	if (isset($wlcfg['channel'])) {
2610
		if ($wlcfg['channel'] == "0") {
2611
			$wlcmd[] = "channel any";
2612
		} else {
2613
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2614
		}
2615
	}
2616

    
2617
	/* Set antenna diversity value */
2618
	if (isset($wlcfg['diversity'])) {
2619
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2620
	}
2621

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

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

    
2632
	/* set Distance value */
2633
	if ($wlcfg['distance']) {
2634
		$distance = escapeshellarg($wlcfg['distance']);
2635
	}
2636

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

    
2644
	/* Set wireless adhoc mode */
2645
	if ($wlcfg['mode'] == "adhoc") {
2646
		$wlcmd[] = "mediaopt adhoc";
2647
	} else {
2648
		$wlcmd[] = "-mediaopt adhoc";
2649
	}
2650

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

    
2653
	/* handle hide ssid option */
2654
	if (isset($wlcfg['hidessid']['enable'])) {
2655
		$wlcmd[] = "hidessid";
2656
	} else {
2657
		$wlcmd[] = "-hidessid";
2658
	}
2659

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

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

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

    
2681
	/* handle turbo option */
2682
	if (isset($wlcfg['turbo']['enable'])) {
2683
		$wlcmd[] = "mediaopt turbo";
2684
	} else {
2685
		$wlcmd[] = "-mediaopt turbo";
2686
	}
2687

    
2688
	/* handle txpower setting */
2689
	// or don't. this has issues at the moment.
2690
	/*
2691
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2692
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2693
	}*/
2694

    
2695
	/* handle wme option */
2696
	if (isset($wlcfg['wme']['enable'])) {
2697
		$wlcmd[] = "wme";
2698
	} else {
2699
		$wlcmd[] = "-wme";
2700
	}
2701

    
2702
	/* Enable wpa if it's configured. No WEP support anymore. */
2703
	if (isset($wlcfg['wpa']['enable'])) {
2704
		$wlcmd[] = "authmode wpa wepmode off ";
2705
	} else {
2706
		$wlcmd[] = "authmode open wepmode off ";
2707
	}
2708

    
2709
	kill_hostapd($if);
2710
	mwexec(kill_wpasupplicant("{$if}"));
2711

    
2712
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2713
	conf_mount_rw();
2714

    
2715
	switch ($wlcfg['mode']) {
2716
		case 'bss':
2717
			if (isset($wlcfg['wpa']['enable'])) {
2718
				$wpa .= <<<EOD
2719
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2720
ctrl_interface_group=0
2721
ap_scan=1
2722
#fast_reauth=1
2723
network={
2724
ssid="{$wlcfg['ssid']}"
2725
scan_ssid=1
2726
priority=5
2727
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2728
psk="{$wlcfg['wpa']['passphrase']}"
2729
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2730
group={$wlcfg['wpa']['wpa_pairwise']}
2731
}
2732
EOD;
2733

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

    
2768
EOD;
2769

    
2770
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2771
					$wpa .= <<<EOD
2772
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
2773
rsn_preauth=1
2774
rsn_preauth_interfaces={$if}
2775

    
2776
EOD;
2777
				}
2778
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2779
					$wpa .= "ieee8021x=1\n";
2780

    
2781
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2782
						$auth_server_port = "1812";
2783
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2784
							$auth_server_port = intval($wlcfg['auth_server_port']);
2785
						}
2786
						$wpa .= <<<EOD
2787

    
2788
auth_server_addr={$wlcfg['auth_server_addr']}
2789
auth_server_port={$auth_server_port}
2790
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2791

    
2792
EOD;
2793
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2794
							$auth_server_port2 = "1812";
2795
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2796
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2797
							}
2798

    
2799
							$wpa .= <<<EOD
2800
auth_server_addr={$wlcfg['auth_server_addr2']}
2801
auth_server_port={$auth_server_port2}
2802
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2803

    
2804
EOD;
2805
						}
2806
					}
2807
				}
2808

    
2809
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2810
				unset($wpa);
2811
			}
2812
			break;
2813
	}
2814

    
2815
	/*
2816
	 *    all variables are set, lets start up everything
2817
	 */
2818

    
2819
	$baseif = interface_get_wireless_base($if);
2820
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2821
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2822

    
2823
	/* set sysctls for the wireless interface */
2824
	if (!empty($wl_sysctl)) {
2825
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2826
		foreach ($wl_sysctl as $wl_sysctl_line) {
2827
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2828
		}
2829
	}
2830

    
2831
	/* set ack timers according to users preference (if he/she has any) */
2832
	if ($distance) {
2833
		fwrite($fd_set, "# Enable ATH distance settings\n");
2834
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2835
	}
2836

    
2837
	if (isset($wlcfg['wpa']['enable'])) {
2838
		if ($wlcfg['mode'] == "bss") {
2839
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2840
		}
2841
		if ($wlcfg['mode'] == "hostap") {
2842
			/* add line to script to restore old mac to make hostapd happy */
2843
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2844
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2845
				if (is_macaddr($if_oldmac)) {
2846
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2847
						" link " . escapeshellarg($if_oldmac) . "\n");
2848
				}
2849
			}
2850

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

    
2853
			/* add line to script to restore spoofed mac after running hostapd */
2854
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2855
				if ($wl['spoofmac']) {
2856
					$if_curmac = $wl['spoofmac'];
2857
				} else {
2858
					$if_curmac = get_interface_mac($if);
2859
				}
2860
				if (is_macaddr($if_curmac)) {
2861
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2862
						" link " . escapeshellarg($if_curmac) . "\n");
2863
				}
2864
			}
2865
		}
2866
	}
2867

    
2868
	fclose($fd_set);
2869
	conf_mount_ro();
2870

    
2871
	/* Making sure regulatory settings have actually changed
2872
	 * before applying, because changing them requires bringing
2873
	 * down all wireless networks on the interface. */
2874
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2875
	$ifconfig_str = implode($output);
2876
	unset($output);
2877
	$reg_changing = false;
2878

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

    
2892
	if ($reg_changing) {
2893
		/* set regulatory domain */
2894
		if ($wlcfg['regdomain']) {
2895
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2896
		}
2897

    
2898
		/* set country */
2899
		if ($wlcfg['regcountry']) {
2900
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2901
		}
2902

    
2903
		/* set location */
2904
		if ($wlcfg['reglocation']) {
2905
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2906
		}
2907

    
2908
		$wlregcmd_args = implode(" ", $wlregcmd);
2909

    
2910
		/* build a complete list of the wireless clones for this interface */
2911
		$clone_list = array();
2912
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2913
			$clone_list[] = interface_get_wireless_clone($baseif);
2914
		}
2915
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2916
			foreach ($config['wireless']['clone'] as $clone) {
2917
				if ($clone['if'] == $baseif) {
2918
					$clone_list[] = $clone['cloneif'];
2919
				}
2920
			}
2921
		}
2922

    
2923
		/* find which clones are up and bring them down */
2924
		$clones_up = array();
2925
		foreach ($clone_list as $clone_if) {
2926
			$clone_status = pfSense_get_interface_addresses($clone_if);
2927
			if ($clone_status['status'] == 'up') {
2928
				$clones_up[] = $clone_if;
2929
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2930
			}
2931
		}
2932

    
2933
		/* apply the regulatory settings */
2934
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2935
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2936

    
2937
		/* bring the clones back up that were previously up */
2938
		foreach ($clones_up as $clone_if) {
2939
			interfaces_bring_up($clone_if);
2940

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

    
2957
	/* 20150318 cmb - Note: the below no longer appears to be true on FreeBSD 10.x, so don't set
2958
	 * mode twice (for now at least). This can be removed entirely in the future if no problems are found
2959

    
2960
	 * The mode must be specified in a separate command before ifconfig
2961
	 * will allow the mode and channel at the same time in the next. */
2962
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2963
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2964

    
2965
	/* configure wireless */
2966
	$wlcmd_args = implode(" ", $wlcmd);
2967
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2968
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2969
	fclose($wlan_setup_log);
2970

    
2971
	unset($wlcmd_args, $wlcmd);
2972

    
2973

    
2974
	sleep(1);
2975
	/* execute hostapd and wpa_supplicant if required in shell */
2976
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2977

    
2978
	return 0;
2979

    
2980
}
2981

    
2982
function kill_hostapd($interface) {
2983
	global $g;
2984

    
2985
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2986
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2987
	}
2988
}
2989

    
2990
function kill_wpasupplicant($interface) {
2991
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2992
}
2993

    
2994
function find_dhclient_process($interface) {
2995
	if ($interface) {
2996
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2997
	} else {
2998
		$pid = 0;
2999
	}
3000

    
3001
	return intval($pid);
3002
}
3003

    
3004
function kill_dhclient_process($interface) {
3005
	if (empty($interface) || !does_interface_exist($interface)) {
3006
		return;
3007
	}
3008

    
3009
	$i = 0;
3010
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3011
		/* 3rd time make it die for sure */
3012
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3013
		posix_kill($pid, $sig);
3014
		sleep(1);
3015
		$i++;
3016
	}
3017
	unset($i);
3018
}
3019

    
3020
function find_dhcp6c_process($interface) {
3021
	global $g;
3022

    
3023
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3024
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3025
	} else {
3026
		return(false);
3027
	}
3028

    
3029
	return intval($pid);
3030
}
3031

    
3032
function kill_dhcp6client_process($interface) {
3033
 	if (empty($interface) || !does_interface_exist($interface)) {
3034
 		return;
3035
 	}
3036

    
3037
 	$i = 0;
3038
 	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3039
 		/* 3rd time make it die for sure */
3040
 		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3041
 		posix_kill($pid, $sig);
3042
 		sleep(1);
3043
 		$i++;
3044
 	}
3045
 	unset($i);
3046
}
3047

    
3048
function interface_virtual_create($interface) {
3049
	global $config;
3050

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

    
3090
function interface_vlan_mtu_configured($iface) {
3091
	global $config;
3092

    
3093
	$mtu = 0;
3094
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3095
		foreach ($config['vlans']['vlan'] as $vlan) {
3096

    
3097
			if ($vlan['vlanif'] != $iface)
3098
				continue;
3099

    
3100
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3101
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3102
				/* VLAN MTU */
3103
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3104
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3105
				/* Parent MTU */
3106
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3107
			}
3108
		}
3109
	}
3110

    
3111
	return $mtu;
3112
}
3113

    
3114
function interface_mtu_wanted_for_pppoe($realif) {
3115
	global $config;
3116

    
3117
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3118
		return 0;
3119

    
3120
	$mtu = 0;
3121
	foreach ($config['ppps']['ppp'] as $ppp) {
3122
		if ($ppp['type'] != "pppoe") {
3123
			continue;
3124
		}
3125

    
3126
		$mtus = array();
3127
		if (!empty($ppp['mtu'])) {
3128
			$mtus = explode(',', $ppp['mtu']);
3129
		}
3130
		$ports = explode(',', $ppp['ports']);
3131

    
3132
		foreach ($ports as $pid => $port) {
3133
			$parentifa = get_parent_interface($port);
3134
			$parentif = $parentifa[0];
3135
			if ($parentif != $realif)
3136
				continue;
3137

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

    
3154
	return $mtu;
3155
}
3156

    
3157
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3158
	global $config, $g;
3159
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3160
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3161

    
3162
	$wancfg = $config['interfaces'][$interface];
3163

    
3164
	if (!isset($wancfg['enable'])) {
3165
		return;
3166
	}
3167

    
3168
	$realif = get_real_interface($interface);
3169
	$realhwif_array = get_parent_interface($interface);
3170
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3171
	$realhwif = $realhwif_array[0];
3172

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

    
3194
		/* only bring down the interface when both v4 and v6 are set to NONE */
3195
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3196
			interface_bring_down($interface);
3197
		}
3198
	}
3199

    
3200
	$interface_to_check = $realif;
3201
	if (interface_isppp_type($interface)) {
3202
		$interface_to_check = $realhwif;
3203
	}
3204

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

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

    
3216
	/* wireless configuration? */
3217
	if (is_array($wancfg['wireless'])) {
3218
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3219
	}
3220

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

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

    
3247
	/* media */
3248
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3249
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3250
		if ($wancfg['media']) {
3251
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3252
		}
3253
		if ($wancfg['mediaopt']) {
3254
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3255
		}
3256
		mwexec($cmd);
3257
	}
3258

    
3259
	/* Apply hw offloading policies as configured */
3260
	enable_hardware_offloading($interface);
3261

    
3262
	/* invalidate interface/ip/sn cache */
3263
	get_interface_arr(true);
3264
	unset($interface_ip_arr_cache[$realif]);
3265
	unset($interface_sn_arr_cache[$realif]);
3266
	unset($interface_ipv6_arr_cache[$realif]);
3267
	unset($interface_snv6_arr_cache[$realif]);
3268

    
3269
	$tunnelif = substr($realif, 0, 3);
3270

    
3271
	$mtuif = $realif;
3272
	$mtuhwif = $realhwif;
3273

    
3274
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3275
	if (interface_isppp_type($interface)) {
3276
		$mtuif = $realhwif;
3277
		$mtuhwif_array = get_parent_interface($mtuif);
3278
		$mtuhwif = $mtuhwif_array[0];
3279
	}
3280

    
3281
	$wantedmtu = 0;
3282
	if (is_array($config['interfaces'])) {
3283
		foreach ($config['interfaces'] as $tmpinterface) {
3284
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3285
				$wantedmtu = $tmpinterface['mtu'];
3286
				break;
3287
			}
3288
		}
3289
	}
3290

    
3291
	/* MTU is not specified for interface, try the pppoe settings. */
3292
	if ($wantedmtu == 0) {
3293
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3294
	}
3295
	if ($wantedmtu == 0 && stristr($mtuif, "_vlan") && interface_isppp_type($interface)) {
3296
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3297
	}
3298

    
3299
	/* Set the MTU to 1500 if no explicit MTU configured. */
3300
	if ($wantedmtu == 0) {
3301
		$wantedmtu = 1500; /* Default */
3302
	}
3303

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

    
3313
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3314

    
3315
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3316
			$configuredmtu = $parentmtu;
3317
		if ($configuredmtu != 0)
3318
			$mtu = $configuredmtu;
3319
		else
3320
			$mtu = $wantedmtu;
3321

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

    
3347
	if (does_interface_exist($wancfg['if'])) {
3348
		interfaces_bring_up($wancfg['if']);
3349
	}
3350

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

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

    
3402
	interface_netgraph_needed($interface);
3403

    
3404
	if (!platform_booting()) {
3405
		link_interface_to_vips($interface, "update");
3406

    
3407
		if ($tunnelif != 'gre') {
3408
			unset($gre);
3409
			$gre = link_interface_to_gre($interface);
3410
			if (!empty($gre)) {
3411
				array_walk($gre, 'interface_gre_configure');
3412
			}
3413
		}
3414

    
3415
		if ($tunnelif != 'gif') {
3416
			unset($gif);
3417
			$gif = link_interface_to_gif ($interface);
3418
			if (!empty($gif)) {
3419
				array_walk($gif, 'interface_gif_configure');
3420
			}
3421
		}
3422

    
3423
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3424
			unset($bridgetmp);
3425
			$bridgetmp = link_interface_to_bridge($interface);
3426
			if (!empty($bridgetmp)) {
3427
				interface_bridge_add_member($bridgetmp, $realif);
3428
			}
3429
		}
3430

    
3431
		$grouptmp = link_interface_to_group($interface);
3432
		if (!empty($grouptmp)) {
3433
			array_walk($grouptmp, 'interface_group_add_member');
3434
		}
3435

    
3436
		if ($interface == "lan") {
3437
			/* make new hosts file */
3438
			system_hosts_generate();
3439
		}
3440

    
3441
		if ($reloadall == true) {
3442

    
3443
			/* reconfigure static routes (kernel may have deleted them) */
3444
			system_routing_configure($interface);
3445

    
3446
			/* reload ipsec tunnels */
3447
			send_event("service reload ipsecdns");
3448

    
3449
			if (isset($config['dnsmasq']['enable'])) {
3450
				services_dnsmasq_configure();
3451
			}
3452

    
3453
			if (isset($config['unbound']['enable'])) {
3454
				services_unbound_configure();
3455
			}
3456

    
3457
			/* update dyndns */
3458
			send_event("service reload dyndns {$interface}");
3459

    
3460
			/* reload captive portal */
3461
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3462
				require_once('captiveportal.inc');
3463
			}
3464
			captiveportal_init_rules_byinterface($interface);
3465
		}
3466
	}
3467

    
3468
	interfaces_staticarp_configure($interface);
3469
	return 0;
3470
}
3471

    
3472
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3473
	global $config, $g;
3474

    
3475
	if (!is_array($wancfg)) {
3476
		return;
3477
	}
3478

    
3479
	if (!isset($wancfg['enable'])) {
3480
		return;
3481
	}
3482

    
3483
	/* If the interface is not configured via another, exit */
3484
	if (empty($wancfg['track6-interface'])) {
3485
		return;
3486
	}
3487

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

    
3498
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3499
	if (!isset($trackcfg['enable'])) {
3500
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
3501
		return;
3502
	}
3503

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

    
3534
	if ($linkupevent == false && !platform_booting()) {
3535
		if (!function_exists('services_dhcpd_configure')) {
3536
			require_once("services.inc");
3537
		}
3538

    
3539
		if (isset($config['unbound']['enable'])) {
3540
			services_unbound_configure();
3541
		}
3542

    
3543
		if (isset($config['dnsmasq']['enable'])) {
3544
			services_dnsmasq_configure();
3545
		}
3546

    
3547
		services_dhcpd_configure("inet6");
3548
	}
3549

    
3550
	return 0;
3551
}
3552

    
3553
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3554
	global $config, $g;
3555
	global $interface_ipv6_arr_cache;
3556
	global $interface_snv6_arr_cache;
3557

    
3558
	if (!is_array($lancfg)) {
3559
		return;
3560
	}
3561

    
3562
	/* If the interface is not configured via another, exit */
3563
	if (empty($lancfg['track6-interface'])) {
3564
		return;
3565
	}
3566

    
3567
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3568
	if (empty($wancfg)) {
3569
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3570
		return;
3571
	}
3572

    
3573
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3574
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3575
		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']));
3576
		return;
3577
	}
3578
	$hexwanv4 = return_hex_ipv4($ip4address);
3579

    
3580
	/* create the long prefix notation for math, save the prefix length */
3581
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3582
	$rd6prefixlen = $rd6prefix[1];
3583
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3584

    
3585
	/* binary presentation of the prefix for all 128 bits. */
3586
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3587

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

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

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

    
3604
	$lanif = get_real_interface($interface);
3605
	$oip = find_interface_ipv6($lanif);
3606
	if (is_ipaddrv6($oip)) {
3607
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3608
	}
3609
	unset($interface_ipv6_arr_cache[$lanif]);
3610
	unset($interface_snv6_arr_cache[$lanif]);
3611
	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));
3612
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3613

    
3614
	return 0;
3615
}
3616

    
3617
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3618
	global $config, $g;
3619
	global $interface_ipv6_arr_cache;
3620
	global $interface_snv6_arr_cache;
3621

    
3622
	if (!is_array($lancfg)) {
3623
		return;
3624
	}
3625

    
3626
	/* If the interface is not configured via another, exit */
3627
	if (empty($lancfg['track6-interface'])) {
3628
		return;
3629
	}
3630

    
3631
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3632
	if (empty($wancfg)) {
3633
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
3634
		return;
3635
	}
3636

    
3637
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3638
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3639
		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']));
3640
		return;
3641
	}
3642
	$hexwanv4 = return_hex_ipv4($ip4address);
3643

    
3644
	/* create the long prefix notation for math, save the prefix length */
3645
	$sixto4prefix = "2002::";
3646
	$sixto4prefixlen = 16;
3647
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3648

    
3649
	/* binary presentation of the prefix for all 128 bits. */
3650
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3651

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

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

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

    
3674
	return 0;
3675
}
3676

    
3677
function interface_6rd_configure($interface = "wan", $wancfg) {
3678
	global $config, $g;
3679

    
3680
	/* because this is a tunnel interface we can only function
3681
	 *	with a public IPv4 address on the interface */
3682

    
3683
	if (!is_array($wancfg)) {
3684
		return;
3685
	}
3686

    
3687
	if (!is_module_loaded('if_stf.ko')) {
3688
		mwexec('/sbin/kldload if_stf.ko');
3689
	}
3690

    
3691
	$wanif = get_real_interface($interface);
3692
	$ip4address = find_interface_ip($wanif);
3693
	if (!is_ipaddrv4($ip4address)) {
3694
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3695
		return false;
3696
	}
3697
	$hexwanv4 = return_hex_ipv4($ip4address);
3698

    
3699
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3700
		$wancfg['prefix-6rd-v4plen'] = 0;
3701
	}
3702

    
3703
	/* create the long prefix notation for math, save the prefix length */
3704
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3705
	$rd6prefixlen = $rd6prefix[1];
3706
	$brgw = explode('.', $wancfg['gateway-6rd']);
3707
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3708
	$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);
3709
	if (strlen($rd6brgw) < 128) {
3710
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3711
	}
3712
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3713
	unset($brgw);
3714
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3715

    
3716
	/* binary presentation of the prefix for all 128 bits. */
3717
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3718

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

    
3726
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3727
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3728

    
3729

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

    
3750
	/* write out a default router file */
3751
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3752
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3753

    
3754
	$ip4gateway = get_interface_gateway($interface);
3755
	if (is_ipaddrv4($ip4gateway)) {
3756
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3757
	}
3758

    
3759
	/* configure dependent interfaces */
3760
	if (!platform_booting()) {
3761
		link_interface_to_track6($interface, "update");
3762
	}
3763

    
3764
	return 0;
3765
}
3766

    
3767
function interface_6to4_configure($interface = "wan", $wancfg) {
3768
	global $config, $g;
3769

    
3770
	/* because this is a tunnel interface we can only function
3771
	 *	with a public IPv4 address on the interface */
3772

    
3773
	if (!is_array($wancfg)) {
3774
		return;
3775
	}
3776

    
3777
	$wanif = get_real_interface($interface);
3778
	$ip4address = find_interface_ip($wanif);
3779
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3780
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
3781
		return false;
3782
	}
3783

    
3784
	/* create the long prefix notation for math, save the prefix length */
3785
	$stfprefixlen = 16;
3786
	$stfprefix = Net_IPv6::uncompress("2002::");
3787
	$stfarr = explode(":", $stfprefix);
3788
	$v4prefixlen = "0";
3789

    
3790
	/* we need the hex form of the interface IPv4 address */
3791
	$ip4arr = explode(".", $ip4address);
3792
	$hexwanv4 = "";
3793
	foreach ($ip4arr as $octet) {
3794
		$hexwanv4 .= sprintf("%02x", $octet);
3795
	}
3796

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

    
3804
	/* binary presentation of the prefix for all 128 bits. */
3805
	$stfprefixbin = "";
3806
	foreach ($stfarr as $element) {
3807
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3808
	}
3809
	/* just save the left prefix length bits */
3810
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3811

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

    
3816
	/* for the local subnet too. */
3817
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3818
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3819

    
3820
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3821
	$stfbrarr = array();
3822
	$stfbrbinarr = array();
3823
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3824
	foreach ($stfbrbinarr as $bin) {
3825
		$stfbrarr[] = dechex(bindec($bin));
3826
	}
3827
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3828

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

    
3840
	/* setup the stf interface */
3841
	if (!is_module_loaded("if_stf")) {
3842
		mwexec("/sbin/kldload if_stf.ko");
3843
	}
3844
	$stfiface = "{$interface}_stf";
3845
	if (does_interface_exist($stfiface)) {
3846
		pfSense_interface_destroy($stfiface);
3847
	}
3848
	$tmpstfiface = pfSense_interface_create("stf");
3849
	pfSense_interface_rename($tmpstfiface, $stfiface);
3850
	pfSense_interface_flags($stfiface, IFF_LINK2);
3851
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3852

    
3853
	if ($g['debug']) {
3854
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3855
	}
3856

    
3857
	/* write out a default router file */
3858
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3859
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3860

    
3861
	$ip4gateway = get_interface_gateway($interface);
3862
	if (is_ipaddrv4($ip4gateway)) {
3863
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3864
	}
3865

    
3866
	if (!platform_booting()) {
3867
		link_interface_to_track6($interface, "update");
3868
	}
3869

    
3870
	return 0;
3871
}
3872

    
3873
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3874
	global $config, $g;
3875

    
3876
	if (!is_array($wancfg)) {
3877
		return;
3878
	}
3879

    
3880
	$wanif = get_real_interface($interface, "inet6");
3881
	$dhcp6cconf = "";
3882

    
3883
	if ($wancfg['adv_dhcp6_config_file_override']) {
3884
		// DHCP6 Config File Override
3885
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3886
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3887
		// DHCP6 Config File Advanced
3888
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3889
	} else {
3890
		// DHCP6 Config File Basic
3891
		$dhcp6cconf .= "interface {$wanif} {\n";
3892

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

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

    
3917
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3918
			$dhcp6cconf .= "\trequest domain-name;\n";
3919
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3920
			$dhcp6cconf .= "};\n";
3921

    
3922
			if (!isset($wancfg['dhcp6prefixonly'])) {
3923
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3924
			}
3925

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

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

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

    
3972
	$rtsoldscript = "#!/bin/sh\n";
3973
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3974
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3975
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3976
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Received RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3977
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3978
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3979
	$rtsoldscript .= "\t/bin/sleep 1\n";
3980
	$rtsoldscript .= "fi\n";
3981
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3982
	$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3983
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3984
	/* non ipoe Process */
3985
 	if (!isset($wancfg['dhcp6withoutra'])) {
3986
		$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3987
		$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3988
		$rtsoldscript .= "\t/bin/sleep 1\n";
3989
		$rtsoldscript .= "fi\n";
3990
	} else {
3991
		$rtsoldscript .= "\t/bin/sleep 1\n";
3992
	}
3993
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3994
	if (!isset($wancfg['dhcp6withoutra'])) {
3995
		$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3996
		$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3997
	}
3998
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3999
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4000
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4001
		unset($rtsoldscript);
4002
		return 1;
4003
	}
4004
	unset($rtsoldscript);
4005
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4006

    
4007
	/* accept router advertisements for this interface */
4008
	log_error("Accept router advertisements on interface {$wanif} ");
4009
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4010

    
4011
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
4012
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4013
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4014
		sleep(2);
4015
	}
4016
	if (isset($wancfg['dhcp6withoutra'])) {
4017
		kill_dhcp6client_process($wanif);
4018

    
4019
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} -c {$g['varetc_path']}/dhcp6c_wan.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}");
4020
 		mwexec("/usr/bin/logger -t mwtag 'Starting dhcp6 client for interface wan({$wanif} in IPoE mode)'");
4021
	}
4022
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
4023

    
4024
	/* NOTE: will be called from rtsold invoked script
4025
	 * link_interface_to_track6($interface, "update");
4026
	 */
4027

    
4028
	return 0;
4029
}
4030

    
4031
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4032
	global $g;
4033

    
4034
	$send_options = "";
4035
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4036
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4037
		foreach ($options as $option) {
4038
			$send_options .= "\tsend " . trim($option) . ";\n";
4039
		}
4040
	}
4041

    
4042
	$request_options = "";
4043
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4044
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4045
		foreach ($options as $option) {
4046
			$request_options .= "\trequest " . trim($option) . ";\n";
4047
		}
4048
	}
4049

    
4050
	$information_only = "";
4051
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4052
		$information_only = "\tinformation-only;\n";
4053
	}
4054

    
4055
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4056
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4057
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4058
	}
4059

    
4060
	$interface_statement  = "interface";
4061
	$interface_statement .= " {$wanif}";
4062
	$interface_statement .= " {\n";
4063
	$interface_statement .= "$send_options";
4064
	$interface_statement .= "$request_options";
4065
	$interface_statement .= "$information_only";
4066
	$interface_statement .= "$script";
4067
	$interface_statement .= "};\n";
4068

    
4069
	$id_assoc_statement_address = "";
4070
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4071
		$id_assoc_statement_address .= "id-assoc";
4072
		$id_assoc_statement_address .= " na";
4073
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4074
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4075
		}
4076
		$id_assoc_statement_address .= " { ";
4077

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

    
4091
		$id_assoc_statement_address .= "};\n";
4092
	}
4093

    
4094
	$id_assoc_statement_prefix = "";
4095
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4096
		$id_assoc_statement_prefix .= "id-assoc";
4097
		$id_assoc_statement_prefix .= " pd";
4098
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4099
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4100
		}
4101
		$id_assoc_statement_prefix .= " { ";
4102

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

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

    
4128
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4129
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4130
			$id_assoc_statement_prefix .= "\n";
4131
		}
4132

    
4133
		$id_assoc_statement_prefix .= "};\n";
4134
	}
4135

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

    
4152
	$key_info_statement = "";
4153
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4154
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4155
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4156
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4157
		$key_info_statement .= "keyinfo";
4158
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4159
		$key_info_statement .= " {\n";
4160
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4161
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4162
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4163
		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'])) {
4164
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4165
		}
4166
		$key_info_statement .= "};\n";
4167
	}
4168

    
4169
	$dhcp6cconf  = $interface_statement;
4170
	$dhcp6cconf .= $id_assoc_statement_address;
4171
	$dhcp6cconf .= $id_assoc_statement_prefix;
4172
	$dhcp6cconf .= $authentication_statement;
4173
	$dhcp6cconf .= $key_info_statement;
4174

    
4175
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4176

    
4177
	return $dhcp6cconf;
4178
}
4179

    
4180

    
4181
function DHCP6_Config_File_Override($wancfg, $wanif) {
4182

    
4183
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4184

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

    
4193

    
4194
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4195

    
4196
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4197

    
4198
	return $dhcp6cconf;
4199
}
4200

    
4201

    
4202
function interface_dhcp_configure($interface = "wan") {
4203
	global $config, $g;
4204

    
4205
	$wancfg = $config['interfaces'][$interface];
4206
	$wanif = $wancfg['if'];
4207
	if (empty($wancfg)) {
4208
		$wancfg = array();
4209
	}
4210

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

    
4218
	if ($wancfg['dhcphostname']) {
4219
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4220
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4221
	} else {
4222
		$dhclientconf_hostname = "";
4223
	}
4224

    
4225
	$wanif = get_real_interface($interface);
4226
	if (empty($wanif)) {
4227
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4228
		return 0;
4229
	}
4230
	$dhclientconf = "";
4231

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

    
4242
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4243
		$dhclientconf .= <<<EOD
4244

    
4245
	reject {$wancfg['dhcprejectfrom']};
4246
EOD;
4247
	}
4248
	$dhclientconf .= <<<EOD
4249

    
4250
}
4251

    
4252
EOD;
4253

    
4254
	// DHCP Config File Advanced
4255
	if ($wancfg['adv_dhcp_config_advanced']) {
4256
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4257
	}
4258

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

    
4268
EOD;
4269
	}
4270

    
4271
	// DHCP Config File Override
4272
	if ($wancfg['adv_dhcp_config_file_override']) {
4273
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4274
	}
4275

    
4276
	fwrite($fd, $dhclientconf);
4277
	fclose($fd);
4278

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

    
4286
	/* Make sure dhclient is not running */
4287
	kill_dhclient_process($wanif);
4288

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

    
4292
	return 0;
4293
}
4294

    
4295
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4296

    
4297
	$hostname = "";
4298
	if ($wancfg['dhcphostname'] != '') {
4299
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4300
	}
4301

    
4302
	/* DHCP Protocol Timings */
4303
	$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");
4304
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4305
		$pt_variable = "{$Protocol_Timing}";
4306
		${$pt_variable} = "";
4307
		if ($wancfg[$Protocol_Timing] != "") {
4308
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4309
		}
4310
	}
4311

    
4312
	$send_options = "";
4313
	if ($wancfg['adv_dhcp_send_options'] != '') {
4314
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp_send_options']);
4315
		foreach ($options as $option) {
4316
			$send_options .= "\tsend " . trim($option) . ";\n";
4317
		}
4318
	}
4319

    
4320
	$request_options = "";
4321
	if ($wancfg['adv_dhcp_request_options'] != '') {
4322
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4323
	}
4324

    
4325
	$required_options = "";
4326
	if ($wancfg['adv_dhcp_required_options'] != '') {
4327
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4328
	}
4329

    
4330
	$option_modifiers = "";
4331
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4332
		$modifiers = DHCP_Config_Option_Split($wancfg['adv_dhcp_option_modifiers']);
4333
		foreach ($modifiers as $modifier) {
4334
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4335
		}
4336
	}
4337

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

    
4361
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4362

    
4363
	return $dhclientconf;
4364
}
4365

    
4366
function DHCP_Config_Option_Split($option_string) {
4367
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
4368
	return $matches ? $matches[0] : [];
4369
}
4370

    
4371
function DHCP_Config_File_Override($wancfg, $wanif) {
4372

    
4373
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4374

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

    
4383

    
4384
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4385

    
4386
	/* Apply Interface Substitutions */
4387
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4388

    
4389
	/* Apply Hostname Substitutions */
4390
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4391

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

    
4398
	/* Apply MAC Address Substitutions */
4399
	foreach ($various_mac_types as $various_mac_type) {
4400
		foreach ($various_mac_cases as $various_mac_case) {
4401
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4402

    
4403
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4404
				if ($res !== false) {
4405

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

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

    
4426
					/* MAC Address Delimiter Substitutions */
4427
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4428

    
4429
					/* Apply MAC Address Substitutions */
4430
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4431
				}
4432
			}
4433
		}
4434
	}
4435

    
4436
	return $dhclientconf;
4437
}
4438

    
4439
function interfaces_group_setup() {
4440
	global $config;
4441

    
4442
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4443
		return;
4444
	}
4445

    
4446
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4447
		interface_group_setup($groupar);
4448
	}
4449

    
4450
	return;
4451
}
4452

    
4453
function interface_group_setup(&$groupname /* The parameter is an array */) {
4454
	global $config;
4455

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

    
4467
	return;
4468
}
4469

    
4470
function is_interface_group($if) {
4471
	global $config;
4472

    
4473
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4474
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4475
			if ($groupentry['ifname'] === $if) {
4476
				return true;
4477
			}
4478
		}
4479
	}
4480

    
4481
	return false;
4482
}
4483

    
4484
function interface_group_add_member($interface, $groupname) {
4485
	$interface = get_real_interface($interface);
4486
	if (does_interface_exist($interface)) {
4487
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4488
	}
4489
}
4490

    
4491
/* COMPAT Function */
4492
function convert_friendly_interface_to_real_interface_name($interface) {
4493
	return get_real_interface($interface);
4494
}
4495

    
4496
/* COMPAT Function */
4497
function get_real_wan_interface($interface = "wan") {
4498
	return get_real_interface($interface);
4499
}
4500

    
4501
/* COMPAT Function */
4502
function get_current_wan_address($interface = "wan") {
4503
	return get_interface_ip($interface);
4504
}
4505

    
4506
/*
4507
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4508
 */
4509
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4510
	global $config;
4511

    
4512
	/* XXX: For speed reasons reference directly the interface array */
4513
	$ifdescrs = &$config['interfaces'];
4514
	//$ifdescrs = get_configured_interface_list(false, true);
4515

    
4516
	foreach ($ifdescrs as $if => $ifname) {
4517
		if ($if == $interface || $ifname['if'] == $interface) {
4518
			return $if;
4519
		}
4520

    
4521
		if (get_real_interface($if) == $interface) {
4522
			return $if;
4523
		}
4524

    
4525
		if ($checkparent == false) {
4526
			continue;
4527
		}
4528

    
4529
		$int = get_parent_interface($if, true);
4530
		if (is_array($int)) {
4531
			foreach ($int as $iface) {
4532
				if ($iface == $interface) {
4533
					return $if;
4534
				}
4535
			}
4536
		}
4537
	}
4538

    
4539
	if ($interface == "enc0") {
4540
		return 'IPsec';
4541
	}
4542
}
4543

    
4544
/* attempt to resolve interface to friendly descr */
4545
function convert_friendly_interface_to_friendly_descr($interface) {
4546
	global $config;
4547

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

    
4601
	return $ifdesc;
4602
}
4603

    
4604
function convert_real_interface_to_friendly_descr($interface) {
4605

    
4606
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4607

    
4608
	if (!empty($ifdesc)) {
4609
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4610
	}
4611

    
4612
	return $interface;
4613
}
4614

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

    
4627
	$parents = array();
4628
	//Check that we got a valid interface passed
4629
	$realif = get_real_interface($interface);
4630
	if ($realif == NULL) {
4631
		return $parents;
4632
	}
4633

    
4634
	// If we got a real interface, find it's friendly assigned name
4635
	if ($interface == $realif && $avoidrecurse == false) {
4636
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4637
	}
4638

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

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

    
4692
	if (empty($parents)) {
4693
		$parents[0] = $realif;
4694
	}
4695

    
4696
	return $parents;
4697
}
4698

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

    
4707
	$realif = get_parent_interface($interface);
4708

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

    
4720
function interface_is_wireless_clone($wlif) {
4721
	if (!stristr($wlif, "_wlan")) {
4722
		return false;
4723
	} else {
4724
		return true;
4725
	}
4726
}
4727

    
4728
function interface_get_wireless_base($wlif) {
4729
	if (!stristr($wlif, "_wlan")) {
4730
		return $wlif;
4731
	} else {
4732
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4733
	}
4734
}
4735

    
4736
function interface_get_wireless_clone($wlif) {
4737
	if (!stristr($wlif, "_wlan")) {
4738
		return $wlif . "_wlan0";
4739
	} else {
4740
		return $wlif;
4741
	}
4742
}
4743

    
4744
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4745
	global $config, $g;
4746

    
4747
	$wanif = NULL;
4748

    
4749
	switch ($interface) {
4750
		case "l2tp":
4751
			$wanif = "l2tp";
4752
			break;
4753
		case "pptp":
4754
			$wanif = "pptp";
4755
			break;
4756
		case "pppoe":
4757
			$wanif = "pppoe";
4758
			break;
4759
		case "openvpn":
4760
			$wanif = "openvpn";
4761
			break;
4762
		case "IPsec":
4763
		case "ipsec":
4764
		case "enc0":
4765
			$wanif = "enc0";
4766
			break;
4767
		case "ppp":
4768
			$wanif = "ppp";
4769
			break;
4770
		default:
4771
			if (substr($interface, 0, 4) == '_vip') {
4772
				$wanif = get_configured_vip_interface($interface);
4773
				if (!empty($wanif)) {
4774
					$wanif = get_real_interface($wanif);
4775
				}
4776
				break;
4777
			} else if (substr($interface, 0, 5) == '_lloc') {
4778
				$interface = substr($interface, 5);
4779
			} else if (strstr($interface, "_vlan") ||
4780
			    does_interface_exist($interface, $flush)) {
4781
				/*
4782
				 * If a real interface was already passed simply
4783
				 * pass the real interface back.  This encourages
4784
				 * the usage of this function in more cases so that
4785
				 * we can combine logic for more flexibility.
4786
				 */
4787
				$wanif = $interface;
4788
				break;
4789
			}
4790

    
4791
			if (empty($config['interfaces'][$interface])) {
4792
				break;
4793
			}
4794

    
4795
			$cfg = &$config['interfaces'][$interface];
4796

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

    
4853
	return $wanif;
4854
}
4855

    
4856
/* Guess the physical interface by providing a IP address */
4857
function guess_interface_from_ip($ipaddress) {
4858

    
4859
	$family = '';
4860
	if (is_ipaddrv4($ipaddress)) {
4861
		$family = 'inet';
4862
	}
4863
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4864
		$family = 'inet6';
4865
	}
4866

    
4867
	if (empty($family)) {
4868
		return false;
4869
	}
4870

    
4871
	/* create a route table we can search */
4872
	$output = '';
4873
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4874
	$output[0] = trim($output[0], " \n");
4875
	if (!empty($output[0])) {
4876
		return $output[0];
4877
	}
4878

    
4879
	return false;
4880
}
4881

    
4882
/*
4883
 * find_ip_interface($ip): return the interface where an ip is defined
4884
 *   (or if $bits is specified, where an IP within the subnet is defined)
4885
 */
4886
function find_ip_interface($ip, $bits = null) {
4887
	if (!is_ipaddr($ip)) {
4888
		return false;
4889
	}
4890

    
4891
	$isv6ip = is_ipaddrv6($ip);
4892

    
4893
	/* if list */
4894
	$ifdescrs = get_configured_interface_list();
4895

    
4896
	foreach ($ifdescrs as $ifdescr => $ifname) {
4897
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4898
		if (is_null($ifip)) {
4899
			continue;
4900
		}
4901
		if (is_null($bits)) {
4902
			if ($ip == $ifip) {
4903
				$int = get_real_interface($ifname);
4904
				return $int;
4905
			}
4906
		} else {
4907
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4908
				$int = get_real_interface($ifname);
4909
				return $int;
4910
			}
4911
		}
4912
	}
4913

    
4914
	return false;
4915
}
4916

    
4917
/*
4918
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4919
 *   (or if $bits is specified, where an IP within the subnet is found)
4920
 */
4921
function find_virtual_ip_alias($ip, $bits = null) {
4922
	global $config;
4923

    
4924
	if (!is_array($config['virtualip']['vip'])) {
4925
		return false;
4926
	}
4927
	if (!is_ipaddr($ip)) {
4928
		return false;
4929
	}
4930

    
4931
	$isv6ip = is_ipaddrv6($ip);
4932

    
4933
	foreach ($config['virtualip']['vip'] as $vip) {
4934
		if ($vip['mode'] === "ipalias") {
4935
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4936
				continue;
4937
			}
4938
			if (is_null($bits)) {
4939
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4940
					return $vip;
4941
				}
4942
			} else {
4943
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4944
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4945
					return $vip;
4946
				}
4947
			}
4948
		}
4949
	}
4950
	return false;
4951
}
4952

    
4953
function link_interface_to_track6($int, $action = "") {
4954
	global $config;
4955

    
4956
	if (empty($int)) {
4957
		return;
4958
	}
4959

    
4960
	if (is_array($config['interfaces'])) {
4961
		$list = array();
4962
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4963
			if (!isset($ifcfg['enable'])) {
4964
				continue;
4965
			}
4966
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4967
				if ($action == "update") {
4968
					interface_track6_configure($ifname, $ifcfg);
4969
				} else if ($action == "") {
4970
					$list[$ifname] = $ifcfg;
4971
				}
4972
			}
4973
		}
4974
		return $list;
4975
	}
4976
}
4977

    
4978
function interface_find_child_cfgmtu($realiface) {
4979
	global $config;
4980

    
4981
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4982
	$vlans = link_interface_to_vlans($realiface);
4983
	$qinqs = link_interface_to_qinqs($realiface);
4984
	$bridge = link_interface_to_bridge($realiface);
4985
	if (!empty($interface)) {
4986
		$gifs = link_interface_to_gif($interface);
4987
		$gres = link_interface_to_gre($interface);
4988
	} else {
4989
		$gifs = array();
4990
		$gres = array();
4991
	}
4992

    
4993
	$mtu = 0;
4994
	if (is_array($vlans)) {
4995
		foreach ($vlans as $vlan) {
4996
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4997
			if (empty($ifass)) {
4998
				continue;
4999
			}
5000
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5001
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5002
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5003
				}
5004
			}
5005
		}
5006
	}
5007
	if (is_array($qinqs)) {
5008
		foreach ($qinqs as $qinq) {
5009
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5010
			if (empty($ifass)) {
5011
				continue;
5012
			}
5013
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5014
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5015
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5016
				}
5017
			}
5018
		}
5019
	}
5020
	if (is_array($gifs)) {
5021
		foreach ($gifs as $gif) {
5022
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5023
			if (empty($ifass)) {
5024
				continue;
5025
			}
5026
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5027
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5028
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5029
				}
5030
			}
5031
		}
5032
	}
5033
	if (is_array($gres)) {
5034
		foreach ($gres as $gre) {
5035
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5036
			if (empty($ifass)) {
5037
				continue;
5038
			}
5039
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5040
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5041
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5042
				}
5043
			}
5044
		}
5045
	}
5046
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5047
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5048
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5049
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5050
		}
5051
	}
5052
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5053

    
5054
	return $mtu;
5055
}
5056

    
5057
function link_interface_to_vlans($int, $action = "") {
5058
	global $config;
5059

    
5060
	if (empty($int)) {
5061
		return;
5062
	}
5063

    
5064
	if (is_array($config['vlans']['vlan'])) {
5065
		$ifaces = array();
5066
		foreach ($config['vlans']['vlan'] as $vlan) {
5067
			if ($int == $vlan['if']) {
5068
				if ($action == "update") {
5069
					interfaces_bring_up($int);
5070
				} else {
5071
					$ifaces[$vlan['tag']] = $vlan;
5072
				}
5073
			}
5074
		}
5075
		if (!empty($ifaces)) {
5076
			return $ifaces;
5077
		}
5078
	}
5079
}
5080

    
5081
function link_interface_to_qinqs($int, $action = "") {
5082
	global $config;
5083

    
5084
	if (empty($int)) {
5085
		return;
5086
	}
5087

    
5088
	if (is_array($config['qinqs']['qinqentry'])) {
5089
		$ifaces = array();
5090
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5091
			if ($int == $qinq['if']) {
5092
				if ($action == "update") {
5093
					interfaces_bring_up($int);
5094
				} else {
5095
					$ifaces[$qinq['tag']] = $qinq;
5096
				}
5097
			}
5098
		}
5099
		if (!empty($ifaces)) {
5100
			return $ifaces;
5101
		}
5102
	}
5103
}
5104

    
5105
function link_interface_to_vips($int, $action = "", $vhid = '') {
5106
	global $config;
5107

    
5108
	$updatevips = false;
5109
	if (is_array($config['virtualip']['vip'])) {
5110
		$result = array();
5111
		foreach ($config['virtualip']['vip'] as $vip) {
5112
			if (substr($vip['interface'], 0, 4) == "_vip") {
5113
				$iface = get_configured_vip_interface($vip['interface']);
5114
			} else {
5115
				$iface = $vip['interface'];
5116
			}
5117
			if ($int != $iface) {
5118
				continue;
5119
			}
5120
			if ($action == "update") {
5121
				$updatevips = true;
5122
			} else {
5123
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5124
				    substr($vip['interface'], 0, 4) == "_vip") {
5125
					$result[] = $vip;
5126
				}
5127
			}
5128
		}
5129
		if ($updatevips === true) {
5130
			interfaces_vips_configure($int);
5131
		}
5132
		return $result;
5133
	}
5134

    
5135
	return NULL;
5136
}
5137

    
5138
/****f* interfaces/link_interface_to_bridge
5139
 * NAME
5140
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5141
 * INPUTS
5142
 *   $ip
5143
 * RESULT
5144
 *   bridge[0-99]
5145
 ******/
5146
function link_interface_to_bridge($int) {
5147
	global $config;
5148

    
5149
	if (is_array($config['bridges']['bridged'])) {
5150
		foreach ($config['bridges']['bridged'] as $bridge) {
5151
			if (in_array($int, explode(',', $bridge['members']))) {
5152
				return "{$bridge['bridgeif']}";
5153
			}
5154
		}
5155
	}
5156
}
5157

    
5158
function link_interface_to_group($int) {
5159
	global $config;
5160

    
5161
	$result = array();
5162

    
5163
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5164
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5165
			if (in_array($int, explode(" ", $group['members']))) {
5166
				$result[$group['ifname']] = $int;
5167
			}
5168
		}
5169
	}
5170

    
5171
	return $result;
5172
}
5173

    
5174
function link_interface_to_gre($interface) {
5175
	global $config;
5176

    
5177
	$result = array();
5178

    
5179
	if (is_array($config['gres']['gre'])) {
5180
		foreach ($config['gres']['gre'] as $gre) {
5181
			if ($gre['if'] == $interface) {
5182
				$result[] = $gre;
5183
			}
5184
		}
5185
	}
5186

    
5187
	return $result;
5188
}
5189

    
5190
function link_interface_to_gif($interface) {
5191
	global $config;
5192

    
5193
	$result = array();
5194

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

    
5203
	return $result;
5204
}
5205

    
5206
/*
5207
 * find_interface_ip($interface): return the interface ip (first found)
5208
 */
5209
function find_interface_ip($interface, $flush = false) {
5210
	global $interface_ip_arr_cache;
5211
	global $interface_sn_arr_cache;
5212

    
5213
	$interface = str_replace("\n", "", $interface);
5214

    
5215
	if (!does_interface_exist($interface)) {
5216
		return;
5217
	}
5218

    
5219
	/* Setup IP cache */
5220
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5221
		$ifinfo = pfSense_get_interface_addresses($interface);
5222
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5223
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5224
	}
5225

    
5226
	return $interface_ip_arr_cache[$interface];
5227
}
5228

    
5229
/*
5230
 * find_interface_ipv6($interface): return the interface ip (first found)
5231
 */
5232
function find_interface_ipv6($interface, $flush = false) {
5233
	global $interface_ipv6_arr_cache;
5234
	global $interface_snv6_arr_cache;
5235
	global $config;
5236

    
5237
	$interface = trim($interface);
5238
	$interface = get_real_interface($interface);
5239

    
5240
	if (!does_interface_exist($interface)) {
5241
		return;
5242
	}
5243

    
5244
	/* Setup IP cache */
5245
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5246
		$ifinfo = pfSense_get_interface_addresses($interface);
5247
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5248
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5249
	}
5250

    
5251
	return $interface_ipv6_arr_cache[$interface];
5252
}
5253

    
5254
/*
5255
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5256
 */
5257
function find_interface_ipv6_ll($interface, $flush = false) {
5258
	global $interface_llv6_arr_cache;
5259
	global $config;
5260

    
5261
	$interface = str_replace("\n", "", $interface);
5262

    
5263
	if (!does_interface_exist($interface)) {
5264
		return;
5265
	}
5266

    
5267
	/* Setup IP cache */
5268
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5269
		$ifinfo = pfSense_getall_interface_addresses($interface);
5270
		foreach ($ifinfo as $line) {
5271
			if (strstr($line, ":")) {
5272
				$parts = explode("/", $line);
5273
				if (is_linklocal($parts[0])) {
5274
					$ifinfo['linklocal'] = $parts[0];
5275
				}
5276
			}
5277
		}
5278
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5279
	}
5280
	return $interface_llv6_arr_cache[$interface];
5281
}
5282

    
5283
function find_interface_subnet($interface, $flush = false) {
5284
	global $interface_sn_arr_cache;
5285
	global $interface_ip_arr_cache;
5286

    
5287
	$interface = str_replace("\n", "", $interface);
5288
	if (does_interface_exist($interface) == false) {
5289
		return;
5290
	}
5291

    
5292
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5293
		$ifinfo = pfSense_get_interface_addresses($interface);
5294
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5295
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5296
	}
5297

    
5298
	return $interface_sn_arr_cache[$interface];
5299
}
5300

    
5301
function find_interface_subnetv6($interface, $flush = false) {
5302
	global $interface_snv6_arr_cache;
5303
	global $interface_ipv6_arr_cache;
5304

    
5305
	$interface = str_replace("\n", "", $interface);
5306
	if (does_interface_exist($interface) == false) {
5307
		return;
5308
	}
5309

    
5310
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5311
		$ifinfo = pfSense_get_interface_addresses($interface);
5312
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5313
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5314
	}
5315

    
5316
	return $interface_snv6_arr_cache[$interface];
5317
}
5318

    
5319
function ip_in_interface_alias_subnet($interface, $ipalias) {
5320
	global $config;
5321

    
5322
	if (empty($interface) || !is_ipaddr($ipalias)) {
5323
		return false;
5324
	}
5325
	if (is_array($config['virtualip']['vip'])) {
5326
		foreach ($config['virtualip']['vip'] as $vip) {
5327
			switch ($vip['mode']) {
5328
				case "ipalias":
5329
					if ($vip['interface'] <> $interface) {
5330
						break;
5331
					}
5332
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5333
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5334
						return true;
5335
					}
5336
					break;
5337
			}
5338
		}
5339
	}
5340

    
5341
	return false;
5342
}
5343

    
5344
function get_possible_listen_ips($include_ipv6_link_local=false) {
5345

    
5346
	$interfaces = get_configured_interface_with_descr();
5347
	foreach ($interfaces as $iface => $ifacename) {
5348
		if ($include_ipv6_link_local) {
5349
			/* This is to avoid going though added ll below */
5350
			if (substr($iface, 0, 5) == '_lloc') {
5351
				continue;
5352
			}
5353
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5354
			if (!empty($llip)) {
5355
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5356
			}
5357
		}
5358
	}
5359
	$viplist = get_configured_vip_list();
5360
	foreach ($viplist as $vip => $address) {
5361
		$interfaces[$vip] = $address;
5362
		if (get_vip_descr($address)) {
5363
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
5364
		}
5365
	}
5366

    
5367
	$interfaces['lo0'] = 'Localhost';
5368

    
5369
	return $interfaces;
5370
}
5371

    
5372
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5373
	global $config;
5374

    
5375
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5376
	foreach (array('server', 'client') as $mode) {
5377
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5378
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5379
				if (!isset($setting['disable'])) {
5380
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5381
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
5382
				}
5383
			}
5384
		}
5385
	}
5386
	return $sourceips;
5387
}
5388

    
5389
function get_interface_ip($interface = "wan") {
5390

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

    
5398
	$realif = get_failover_interface($interface, 'inet');
5399
	if (!$realif) {
5400
		return null;
5401
	}
5402

    
5403
	if (substr($realif, 0, 4) == '_vip') {
5404
		return get_configured_vip_ipv4($realif);
5405
	} else if (substr($realif, 0, 5) == '_lloc') {
5406
		/* No link-local address for v4. */
5407
		return null;
5408
	}
5409

    
5410
	if (is_array($config['interfaces'][$interface]) &&
5411
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
5412
		return ($config['interfaces'][$interface]['ipaddr']);
5413
	}
5414

    
5415
	/*
5416
	 * Beaware that find_interface_ip() is our last option, it will
5417
	 * return the first IP it find on interface, not necessarily the
5418
	 * main IP address.
5419
	 */
5420
	$curip = find_interface_ip($realif);
5421
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5422
		return $curip;
5423
	} else {
5424
		return null;
5425
	}
5426
}
5427

    
5428
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
5429
	global $config;
5430

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

    
5437
	$realif = get_failover_interface($interface, 'inet6');
5438
	if (!$realif) {
5439
		return null;
5440
	}
5441

    
5442
	if (substr($realif, 0, 4) == '_vip') {
5443
		return get_configured_vip_ipv6($realif);
5444
	} else if (substr($realif, 0, 5) == '_lloc') {
5445
		return get_interface_linklocal($realif);
5446
	}
5447

    
5448
	if (is_array($config['interfaces'][$interface])) {
5449
		switch ($config['interfaces'][$interface]['ipaddr']) {
5450
			case 'pppoe':
5451
			case 'l2tp':
5452
			case 'pptp':
5453
			case 'ppp':
5454
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5455
					$realif = get_real_interface($interface, 'inet6', false);
5456
				}
5457
				break;
5458
		}
5459
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
5460
			return ($config['interfaces'][$interface]['ipaddrv6']);
5461
		}
5462
	}
5463

    
5464
	/*
5465
	 * Beaware that find_interface_ip() is our last option, it will
5466
	 * return the first IP it find on interface, not necessarily the
5467
	 * main IP address.
5468
	 */
5469
	$curip = find_interface_ipv6($realif, $flush);
5470
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5471
		return $curip;
5472
	} else {
5473
		/*
5474
		 * NOTE: On the case when only the prefix is requested,
5475
		 * the communication on WAN will be done over link-local.
5476
		 */
5477
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
5478
			$curip = find_interface_ipv6_ll($realif, $flush);
5479
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5480
				return $curip;
5481
			}
5482
		}
5483
	}
5484
	return null;
5485
}
5486

    
5487
function get_interface_linklocal($interface = "wan") {
5488

    
5489
	$realif = get_failover_interface($interface, 'inet6');
5490
	if (!$realif) {
5491
		return null;
5492
	}
5493

    
5494
	if (substr($interface, 0, 4) == '_vip') {
5495
		$realif = get_real_interface($interface);
5496
	} else if (substr($interface, 0, 5) == '_lloc') {
5497
		$realif = get_real_interface(substr($interface, 5));
5498
	}
5499

    
5500
	$curip = find_interface_ipv6_ll($realif);
5501
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5502
		return $curip;
5503
	} else {
5504
		return null;
5505
	}
5506
}
5507

    
5508
function get_interface_subnet($interface = "wan") {
5509

    
5510
	if (substr($interface, 0, 4) == '_vip') {
5511
		return (get_configured_vip_subnetv4($interface));
5512
	}
5513

    
5514
	$realif = get_real_interface($interface);
5515
	if (!$realif) {
5516
		return (NULL);
5517
	}
5518

    
5519
	$cursn = find_interface_subnet($realif);
5520
	if (!empty($cursn)) {
5521
		return ($cursn);
5522
	}
5523

    
5524
	return (NULL);
5525
}
5526

    
5527
function get_interface_subnetv6($interface = "wan") {
5528

    
5529
	if (substr($interface, 0, 4) == '_vip') {
5530
		return (get_configured_vip_subnetv6($interface));
5531
	} else if (substr($interface, 0, 5) == '_lloc') {
5532
		$interface = substr($interface, 5);
5533
	}
5534

    
5535
	$realif = get_real_interface($interface, 'inet6');
5536
	if (!$realif) {
5537
		return (NULL);
5538
	}
5539

    
5540
	$cursn = find_interface_subnetv6($realif);
5541
	if (!empty($cursn)) {
5542
		return ($cursn);
5543
	}
5544

    
5545
	return (NULL);
5546
}
5547

    
5548
/* return outside interfaces with a gateway */
5549
function get_interfaces_with_gateway() {
5550
	global $config;
5551

    
5552
	$ints = array();
5553

    
5554
	/* loop interfaces, check config for outbound */
5555
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5556
		switch ($ifname['ipaddr']) {
5557
			case "dhcp":
5558
			case "pppoe":
5559
			case "pptp":
5560
			case "l2tp":
5561
			case "ppp":
5562
				$ints[$ifdescr] = $ifdescr;
5563
				break;
5564
			default:
5565
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5566
				    !empty($ifname['gateway'])) {
5567
					$ints[$ifdescr] = $ifdescr;
5568
				}
5569
				break;
5570
		}
5571
	}
5572
	return $ints;
5573
}
5574

    
5575
/* return true if interface has a gateway */
5576
function interface_has_gateway($friendly) {
5577
	global $config;
5578

    
5579
	if (!empty($config['interfaces'][$friendly])) {
5580
		$ifname = &$config['interfaces'][$friendly];
5581
		switch ($ifname['ipaddr']) {
5582
			case "dhcp":
5583
			case "pppoe":
5584
			case "pptp":
5585
			case "l2tp":
5586
			case "ppp":
5587
				return true;
5588
			break;
5589
			default:
5590
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5591
					return true;
5592
				}
5593
				$tunnelif = substr($ifname['if'], 0, 3);
5594
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5595
					if (find_interface_ip($ifname['if'])) {
5596
						return true;
5597
					}
5598
				}
5599
				if (!empty($ifname['gateway'])) {
5600
					return true;
5601
				}
5602
			break;
5603
		}
5604
	}
5605

    
5606
	return false;
5607
}
5608

    
5609
/* return true if interface has a gateway */
5610
function interface_has_gatewayv6($friendly) {
5611
	global $config;
5612

    
5613
	if (!empty($config['interfaces'][$friendly])) {
5614
		$ifname = &$config['interfaces'][$friendly];
5615
		switch ($ifname['ipaddrv6']) {
5616
			case "slaac":
5617
			case "dhcp6":
5618
			case "6to4":
5619
			case "6rd":
5620
				return true;
5621
				break;
5622
			default:
5623
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5624
					return true;
5625
				}
5626
				$tunnelif = substr($ifname['if'], 0, 3);
5627
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5628
					if (find_interface_ipv6($ifname['if'])) {
5629
						return true;
5630
					}
5631
				}
5632
				if (!empty($ifname['gatewayv6'])) {
5633
					return true;
5634
				}
5635
				break;
5636
		}
5637
	}
5638

    
5639
	return false;
5640
}
5641

    
5642
/****f* interfaces/is_altq_capable
5643
 * NAME
5644
 *   is_altq_capable - Test if interface is capable of using ALTQ
5645
 * INPUTS
5646
 *   $int            - string containing interface name
5647
 * RESULT
5648
 *   boolean         - true or false
5649
 ******/
5650

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

    
5665
	$int_family = remove_ifindex($int);
5666

    
5667
	if (in_array($int_family, $capable)) {
5668
		return true;
5669
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5670
		return true;
5671
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5672
		return true;
5673
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5674
		return true;
5675
	} else {
5676
		return false;
5677
	}
5678
}
5679

    
5680
/****f* interfaces/is_interface_wireless
5681
 * NAME
5682
 *   is_interface_wireless - Returns if an interface is wireless
5683
 * RESULT
5684
 *   $tmp       - Returns if an interface is wireless
5685
 ******/
5686
function is_interface_wireless($interface) {
5687
	global $config, $g;
5688

    
5689
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5690
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5691
		if (preg_match($g['wireless_regex'], $interface)) {
5692
			if (isset($config['interfaces'][$friendly])) {
5693
				$config['interfaces'][$friendly]['wireless'] = array();
5694
			}
5695
			return true;
5696
		}
5697
		return false;
5698
	} else {
5699
		return true;
5700
	}
5701
}
5702

    
5703
function get_wireless_modes($interface) {
5704
	/* return wireless modes and channels */
5705
	$wireless_modes = array();
5706

    
5707
	$cloned_interface = get_real_interface($interface);
5708

    
5709
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5710
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5711
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5712
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5713

    
5714
		$interface_channels = "";
5715
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5716
		$interface_channel_count = count($interface_channels);
5717

    
5718
		$c = 0;
5719
		while ($c < $interface_channel_count) {
5720
			$channel_line = explode(",", $interface_channels["$c"]);
5721
			$wireless_mode = trim($channel_line[0]);
5722
			$wireless_channel = trim($channel_line[1]);
5723
			if (trim($wireless_mode) != "") {
5724
				/* if we only have 11g also set 11b channels */
5725
				if ($wireless_mode == "11g") {
5726
					if (!isset($wireless_modes["11b"])) {
5727
						$wireless_modes["11b"] = array();
5728
					}
5729
				} else if ($wireless_mode == "11g ht") {
5730
					if (!isset($wireless_modes["11b"])) {
5731
						$wireless_modes["11b"] = array();
5732
					}
5733
					if (!isset($wireless_modes["11g"])) {
5734
						$wireless_modes["11g"] = array();
5735
					}
5736
					$wireless_mode = "11ng";
5737
				} else if ($wireless_mode == "11a ht") {
5738
					if (!isset($wireless_modes["11a"])) {
5739
						$wireless_modes["11a"] = array();
5740
					}
5741
					$wireless_mode = "11na";
5742
				}
5743
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5744
			}
5745
			$c++;
5746
		}
5747
	}
5748
	return($wireless_modes);
5749
}
5750

    
5751
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5752
function get_wireless_channel_info($interface) {
5753
	$wireless_channels = array();
5754

    
5755
	$cloned_interface = get_real_interface($interface);
5756

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

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

    
5765
		foreach ($interface_channels as $channel_line) {
5766
			$channel_line = explode(",", $channel_line);
5767
			if (!isset($wireless_channels[$channel_line[0]])) {
5768
				$wireless_channels[$channel_line[0]] = $channel_line;
5769
			}
5770
		}
5771
	}
5772
	return($wireless_channels);
5773
}
5774

    
5775
function set_interface_mtu($interface, $mtu) {
5776

    
5777
	/* LAGG interface must be destroyed and re-created to change MTU */
5778
	if (substr($interface, 0, 4) == 'lagg') {
5779
		if (isset($config['laggs']['lagg']) &&
5780
		    is_array($config['laggs']['lagg'])) {
5781
			foreach ($config['laggs']['lagg'] as $lagg) {
5782
				if ($lagg['laggif'] == $interface) {
5783
					interface_lagg_configure($lagg);
5784
					break;
5785
				}
5786
			}
5787
		}
5788
	} else {
5789
		pfSense_interface_mtu($interface, $mtu);
5790
	}
5791
}
5792

    
5793
/****f* interfaces/get_interface_mtu
5794
 * NAME
5795
 *   get_interface_mtu - Return the mtu of an interface
5796
 * RESULT
5797
 *   $tmp       - Returns the mtu of an interface
5798
 ******/
5799
function get_interface_mtu($interface) {
5800
	$mtu = pfSense_interface_getmtu($interface);
5801
	return $mtu['mtu'];
5802
}
5803

    
5804
function get_interface_mac($interface) {
5805

    
5806
	$macinfo = pfSense_get_interface_addresses($interface);
5807
	return $macinfo["macaddr"];
5808
}
5809

    
5810
/****f* pfsense-utils/generate_random_mac_address
5811
 * NAME
5812
 *   generate_random_mac - generates a random mac address
5813
 * INPUTS
5814
 *   none
5815
 * RESULT
5816
 *   $mac - a random mac address
5817
 ******/
5818
function generate_random_mac_address() {
5819
	$mac = "02";
5820
	for ($x = 0; $x < 5; $x++) {
5821
		$mac .= ":" . dechex(rand(16, 255));
5822
	}
5823
	return $mac;
5824
}
5825

    
5826
/****f* interfaces/is_jumbo_capable
5827
 * NAME
5828
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5829
 * INPUTS
5830
 *   $int             - string containing interface name
5831
 * RESULT
5832
 *   boolean          - true or false
5833
 ******/
5834
function is_jumbo_capable($iface) {
5835
	$iface = trim($iface);
5836
	$capable = pfSense_get_interface_addresses($iface);
5837

    
5838
	if (isset($capable['caps']['vlanmtu'])) {
5839
		return true;
5840
	}
5841

    
5842
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5843
	if (substr($iface, 0, 4) == "lagg") {
5844
		return true;
5845
	}
5846

    
5847
	return false;
5848
}
5849

    
5850
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5851
	global $g;
5852

    
5853
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5854

    
5855
	if (!empty($iface) && !empty($pppif)) {
5856
		$cron_cmd = <<<EOD
5857
#!/bin/sh
5858
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5859
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5860

    
5861
EOD;
5862

    
5863
		@file_put_contents($cron_file, $cron_cmd);
5864
		chmod($cron_file, 0755);
5865
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5866
	} else {
5867
		unlink_if_exists($cron_file);
5868
	}
5869
}
5870

    
5871
function get_interface_default_mtu($type = "ethernet") {
5872
	switch ($type) {
5873
		case "gre":
5874
			return 1476;
5875
			break;
5876
		case "gif":
5877
			return 1280;
5878
			break;
5879
		case "tun":
5880
		case "vlan":
5881
		case "tap":
5882
		case "ethernet":
5883
		default:
5884
			return 1500;
5885
			break;
5886
	}
5887

    
5888
	/* Never reached */
5889
	return 1500;
5890
}
5891

    
5892
function get_vip_descr($ipaddress) {
5893
	global $config;
5894

    
5895
	foreach ($config['virtualip']['vip'] as $vip) {
5896
		if ($vip['subnet'] == $ipaddress) {
5897
			return ($vip['descr']);
5898
		}
5899
	}
5900
	return "";
5901
}
5902

    
5903
function interfaces_staticarp_configure($if) {
5904
	global $config, $g;
5905
	if (isset($config['system']['developerspew'])) {
5906
		$mt = microtime();
5907
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5908
	}
5909

    
5910
	$ifcfg = $config['interfaces'][$if];
5911

    
5912
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5913
		return 0;
5914
	}
5915

    
5916
	/* Enable staticarp, if enabled */
5917
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5918
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5919
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5920
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5921
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5922
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5923
			}
5924
		}
5925
	} else {
5926
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5927
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5928
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5929
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5930
				if (isset($arpent['arp_table_static_entry'])) {
5931
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5932
				}
5933
			}
5934
		}
5935
	}
5936

    
5937
	return 0;
5938
}
5939

    
5940
function get_failover_interface($interface, $family = "all") {
5941
	global $config;
5942

    
5943
	/* shortcut to get_real_interface if we find it in the config */
5944
	if (is_array($config['interfaces'][$interface])) {
5945
		return get_real_interface($interface, $family);
5946
	}
5947

    
5948
	/* compare against gateway groups */
5949
	$a_groups = return_gateway_groups_array();
5950
	if (is_array($a_groups[$interface])) {
5951
		/* we found a gateway group, fetch the interface or vip */
5952
		if (!empty($a_groups[$interface][0]['vip'])) {
5953
			return $a_groups[$interface][0]['vip'];
5954
		} else {
5955
			return $a_groups[$interface][0]['int'];
5956
		}
5957
	}
5958
	/* fall through to get_real_interface */
5959
	/* XXX: Really needed? */
5960
	return get_real_interface($interface, $family);
5961
}
5962

    
5963
function remove_ifindex($ifname) {
5964
	return preg_replace("/[0-9]+$/", "", $ifname);
5965
}
5966

    
5967
?>
(18-18/53)