Project

General

Profile

Download (137 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	interfaces.inc
5
	Copyright (C) 2004-2008 Scott Ullrich
6
	Copyright (C) 2008-2009 Ermal Lu?i
7
	All rights reserved.
8

    
9
	function interfaces_wireless_configure is
10
	Copyright (C) 2005 Espen Johansen
11
	All rights reserved.
12

    
13
	originally part of m0n0wall (http://m0n0.ch/wall)
14
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
15
	All rights reserved.
16

    
17
	Redistribution and use in source and binary forms, with or without
18
	modification, are permitted provided that the following conditions are met:
19

    
20
	1. Redistributions of source code must retain the above copyright notices,
21
	   this list of conditions and the following disclaimer.
22

    
23
	2. Redistributions in binary form must reproduce the above copyright
24
	   notices, this list of conditions and the following disclaimer in the
25
	   documentation and/or other materials provided with the distribution.
26

    
27
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
28
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
	POSSIBILITY OF SUCH DAMAGE.
37

    
38
	pfSense_BUILDER_BINARIES:	/sbin/dhclient	/bin/sh	/usr/bin/grep	/usr/bin/xargs	/usr/bin/awk	/usr/local/sbin/choparp
39
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig	/sbin/route	/usr/sbin/ngctl	/usr/sbin/arp	/bin/kill	/usr/local/sbin/mpd5
40
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/dhclient
41
	pfSense_MODULE:	interfaces
42

    
43
*/
44

    
45
/* include all configuration functions */
46
require_once("globals.inc");
47
require_once("cmd_chain.inc");
48
require_once("util.inc");
49
require_once("gwlb.inc");
50

    
51
function interfaces_bring_up($interface) {
52
	if(!$interface) {
53
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
54
		log_error( "Backtrace: " . debug_backtrace() );
55
		return;
56
	}
57
	pfSense_interface_flags($interface, IFF_UP);
58
}
59

    
60
/*
61
 * Return the interface array
62
 */
63
function get_interface_arr($flush = false) {
64
        global $interface_arr_cache;
65

    
66
        /* If the cache doesn't exist, build it */
67
        if (!isset($interface_arr_cache) or $flush)
68
                $interface_arr_cache = pfSense_interface_listget();
69

    
70
        return $interface_arr_cache;
71
}
72

    
73
/*
74
 * does_interface_exist($interface): return true or false if a interface is
75
 * detected.
76
 */
77
function does_interface_exist($interface) {
78
	global $config;
79
	
80
	if(!$interface)
81
		return false;
82

    
83
	$ints = get_interface_arr(true);
84
	if (in_array($interface, $ints))
85
		return true;
86
	else
87
		return false;
88
}
89

    
90
/*
91
 * does_vip_exist($vip): return true or false if a vip is
92
 * configured.
93
 */
94
function does_vip_exist($vip) {
95
	global $config;
96
	
97
	if(!$vip)
98
		return false;
99

    
100

    
101
	switch ($vip['mode']) {
102
	case "carp":
103
		$realif = "{$vip['interface']}_vip{$vip['vhid']}";
104
		if (!does_interface_exist($realif)) {
105
			return false;
106
		}
107
		break;
108
	case "ipalias":
109
		$realif = get_real_interface($vip['interface']);
110
		if (!does_interface_exist($realif)) {
111
			return false;
112
		}
113
		break;
114
	case "proxyarp":
115
		/* XXX: Implement this */
116
	default:
117
		return false;
118
	}
119

    
120
	$ifacedata = pfSense_getall_interface_addresses($realif);
121
	foreach ($ifacedata as $vipips) {
122
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}")
123
			return true;
124
	}
125

    
126
	return false;
127
}
128

    
129
function interface_netgraph_needed($interface = "wan") {
130
	global $config;
131

    
132
	$found = false;
133
	if (!empty($config['pptpd']) &&
134
		$config['pptpd']['mode'] == "server")
135
		$found = true;
136
	if ($found == false && !empty($config['l2tp']) &&
137
		$config['l2tp']['mode'] == "server")
138
		$found = true;
139
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
140
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
141
			if ($pppoe['mode'] != "server")
142
				continue;
143
			if ($pppoe['interface'] == $interface)
144
				$found = true;
145
				break;
146
		}
147
	}
148
	if ($found == false) {
149
		if (!empty($config['interfaces'][$interface])) {
150
			switch ($config['interfaces'][$interface]['ipaddr']) {
151
			case "ppp":
152
			case "pppoe":
153
			case "l2tp":
154
			case "pptp":
155
				$found = true;
156
				break;
157
			default:
158
				$found = false;
159
				break;
160
			}
161
		}
162
	}
163
	if ($found == false) {
164
		$realif = get_real_interface($interface);
165
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
166
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
167

    
168
/* This if block doesn't do anything. It can be deleted.
169
PPP interfaces are found above in the previous if ($found == false) block.
170
This block of code is only entered for OPTx interfaces that are configured for PPPoE modem access, so $realif != $ppp['if']
171

    
172
				if ($realif == $ppp['if']) {
173
					$found = true;
174
					break;
175
				}
176
*/			
177
				$ports = explode(',',$ppp['ports']);
178
				foreach($ports as $pid => $port){
179
					$port = get_real_interface($port);
180
					if ($realif == $port) {
181
						$found = true;
182
						break;
183
					}
184
					/* Find the parent interfaces of the vlans in the MLPPP configs 
185
					* there should be only one element in the array here 
186
					* -- this could be better . . . */
187
					$parent_if = get_parent_interface($port);
188
					if ($realif == $parent_if[0]) {
189
						$found = true;
190
						break;
191
					}
192
				}
193
			}
194
		}
195
	}
196
	
197
	if ($found == false) {
198
		$realif = get_real_interface($interface);
199
		pfSense_ngctl_detach("{$realif}:", $realif);
200
	}
201
	/* NOTE: We make sure for this on interface_ppps_configure()
202
	 *	no need to do it here agan.
203
	 *	else
204
	 *		pfSense_ngctl_attach(".", $realif);
205
	 */
206
}
207

    
208
function interfaces_loopback_configure() {
209
	global $g;
210

    
211
	if ($g['platform'] == 'jail')
212
		return;
213
	if($g['booting'])
214
		echo gettext("Configuring loopback interface...");
215
	pfSense_interface_setaddress("lo0", "127.0.0.1");
216
	interfaces_bring_up("lo0");
217
	if($g['booting'])
218
		echo gettext("done.") . "\n";
219
	return 0;
220
}
221

    
222
function interfaces_vlan_configure() {
223
	global $config, $g;
224
	if($g['booting'])
225
		echo gettext("Configuring VLAN interfaces...");
226
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
227
		foreach ($config['vlans']['vlan'] as $vlan) {
228
			if(empty($vlan['vlanif']))
229
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
230
			/* XXX: Maybe we should report any errors?! */
231
			interface_vlan_configure($vlan);
232
		}
233
	}
234
	if($g['booting'])
235
		echo gettext("done.") . "\n";
236
}
237

    
238
function interface_vlan_configure(&$vlan) {
239
        global $config, $g;
240

    
241
	if (!is_array($vlan)) {
242
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
243
		return;
244
	}
245
	$if = $vlan['if'];
246
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
247
	$tag = $vlan['tag'];
248

    
249
	if (empty($if)) {
250
		log_error(gettext("interface_vlan_configure called with if undefined."));
251
		return;
252
	}
253

    
254
	/* make sure the parent interface is up */
255
	interfaces_bring_up($if);
256
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
257
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
258

    
259
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
260
		interface_bring_down($vlanif, true);
261
	} else {
262
		$tmpvlanif = pfSense_interface_create("vlan");
263
		pfSense_interface_rename($tmpvlanif, $vlanif);
264
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
265
	}
266

    
267
	pfSense_vlan_create($vlanif, $if, $tag);
268

    
269
	interfaces_bring_up($vlanif);
270

    
271
	/* invalidate interface cache */
272
	get_interface_arr(true);
273

    
274
	/* XXX: ermal -- for now leave it here at the moment it does not hurt. */
275
	interfaces_bring_up($if);
276

    
277
	return $vlanif;
278
}
279

    
280
function interface_qinq_configure(&$vlan, $fd = NULL) {
281
        global $config, $g;
282

    
283
        if (!is_array($vlan)) {
284
                log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
285
                return;
286
        }
287

    
288
        $qinqif = $vlan['if'];
289
        $tag = $vlan['tag'];
290
        if(empty($qinqif)) {
291
                log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
292
                return;
293
        }
294
	$vlanif = interface_vlan_configure($vlan);
295

    
296
        if ($fd == NULL) {
297
                $exec = true;
298
                $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
299
        } else
300
                $exec = false;
301
        /* make sure the parent is converted to ng_vlan(4) and is up */
302
        interfaces_bring_up($qinqif);
303

    
304
	pfSense_ngctl_attach(".", $qinqif);
305
        if (!empty($vlanif) && does_interface_exist($vlanif)) {
306
                fwrite($fd, "shutdown {$qinqif}qinq:\n");
307
                exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
308
                if (empty($result)) {
309
                        fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
310
                        fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
311
                        fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
312
                }
313
        } else {
314
                fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
315
                fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
316
                fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
317
        }
318

    
319
        /* invalidate interface cache */
320
        get_interface_arr(true);
321

    
322
        if (!stristr($qinqif, "vlan"))
323
                mwexec("/sbin/ifconfig {$qinqif} promisc\n");
324

    
325
        $macaddr = get_interface_mac($qinqif);
326
        if (!empty($vlan['members'])) {
327
                $members = explode(" ", $vlan['members']);
328
                foreach ($members as $qtag) {
329
                        $qinq = array();
330
                        $qinq['tag'] = $qtag;
331
                        $qinq['if'] = $vlanif;
332
                        interface_qinq2_configure($qinq, $fd, $macaddr);
333
                }
334
        }
335
        if ($exec == true) {
336
                fclose($fd);
337
                mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
338
        }
339

    
340
        interfaces_bring_up($qinqif);
341
        if (!empty($vlan['members'])) {
342
                $members = explode(" ", $vlan['members']);
343
                foreach ($members as $qif)
344
                        interfaces_bring_up("{$vlanif}_{$qif}");
345
        }
346

    
347
        return $vlanif;
348
}
349

    
350
function interfaces_qinq_configure() {
351
	global $config, $g;
352
	if($g['booting'])
353
		echo gettext("Configuring QinQ interfaces...");
354
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
355
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
356
			/* XXX: Maybe we should report any errors?! */
357
			interface_qinq_configure($qinq);
358
		}
359
	}
360
	if($g['booting'])
361
		echo gettext( "done.") . "\n";
362
}
363

    
364
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
365
        global $config, $g;
366

    
367
        if (!is_array($qinq)) {
368
                log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
369
                return;
370
        }
371

    
372
        $if = $qinq['if'];
373
        $tag = $qinq['tag'];
374
        $vlanif = "{$if}_{$tag}";
375
        if(empty($if)) {
376
                log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
377
                return;
378
        }
379

    
380
        fwrite($fd, "shutdown {$if}h{$tag}:\n");
381
        fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
382
        fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
383
        fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
384
        fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
385
        fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
386

    
387
        /* invalidate interface cache */
388
        get_interface_arr(true);
389

    
390
        return $vlanif;
391
}
392

    
393
function interfaces_create_wireless_clones() {
394
	global $config;
395

    
396
	if($g['booting'])
397
		echo gettext("Creating other wireless clone interfaces...");
398
	if (is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
399
		foreach ($config['wireless']['clone'] as $clone) {
400
			if(empty($clone['cloneif']))
401
				continue;
402
			if(does_interface_exist($clone['cloneif']))
403
				continue;
404
			/* XXX: Maybe we should report any errors?! */
405
			if(interface_wireless_clone($clone['cloneif'], $clone))
406
				if($g['booting'])
407
					echo " " . $clone['cloneif'];
408
		}
409
	}
410
	if($g['booting'])
411
		echo " " . gettext("done.") . "\n";
412

    
413
}
414

    
415
function interfaces_bridge_configure($checkmember = 0) {
416
        global $config;
417

    
418
        $i = 0;
419
        if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
420
                foreach ($config['bridges']['bridged'] as $bridge) {
421
                        if(empty($bridge['bridgeif']))
422
                                $bridge['bridgeif'] = "bridge{$i}";
423
                        /* XXX: Maybe we should report any errors?! */
424
                        interface_bridge_configure($bridge, $checkmember);
425
                        $i++;
426
                }
427
        }
428
}
429

    
430
function interface_bridge_configure(&$bridge, $checkmember = 0) {
431
	global $config, $g;
432

    
433
	if (!is_array($bridge))
434
	        return -1;
435

    
436
	if (empty($bridge['members'])) {
437
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
438
		return -1;
439
	}
440

    
441
	$members = explode(',', $bridge['members']);
442
	if (!count($members))
443
		return -1;
444

    
445
	/* Calculate smaller mtu and enforce it */
446
	$smallermtu = 0;
447
	$commonrx = true;
448
	$commontx = true;
449
	$foundgif = false;
450
	foreach ($members as $member) {
451
		$realif = get_real_interface($member);
452
		$opts = pfSense_get_interface_addresses($realif);
453
		$mtu = $opts['mtu'];
454
		if (substr($realif, 0, 3) == "gif") {
455
			$foundgif = true;
456
			if ($checkmember == 1)
457
				return;
458
			if ($mtu <= 1500)
459
				continue;
460
		}
461
		if (!isset($opts['encaps']['txcsum']))
462
			$commontx = false;
463
		if (!isset($opts['encaps']['rxcsum']))
464
			$commonrx = false;
465
		if (!isset($opts['encaps']['tso4']))
466
			$commontso4 = false;
467
		if (!isset($opts['encaps']['tso6']))
468
			$commontso6 = false;
469
		if (!isset($opts['encaps']['lro']))
470
			$commonlro = false;
471
		if ($smallermtu == 0 && !empty($mtu))
472
			$smallermtu = $mtu;
473
		else if (!empty($mtu) && $mtu < $smallermtu)
474
			$smallermtu = $mtu;
475
	}
476
	if ($foundgif == false && $checkmember == 2)
477
		return;
478

    
479
	/* Just in case anything is not working well */
480
	if ($smallermtu == 0)
481
		$smallermtu = 1500; 
482

    
483
	$flags = 0;
484
	if ($commonrx === false)
485
		$flags |= IFCAP_RXCSUM;
486
	if ($commontx === false)
487
		$flags |= IFCAP_TXCSUM;
488
	if ($commontso4 === false)
489
		$flags |= IFCAP_TSO4;
490
	if ($commontso6 === false)
491
		$flags |= IFCAP_TSO6;
492
	if ($commonlro === false)
493
		$flags |= IFCAP_LRO;
494

    
495
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
496
		pfSense_interface_destroy($bridge['bridgeif']);
497
		pfSense_interface_create($bridge['bridgeif']);
498
		$bridgeif = $bridge['bridgeif'];
499
	} else
500
		$bridgeif = pfSense_interface_create("bridge");
501

    
502
	$checklist = get_configured_interface_list();
503

    
504
	/* Add interfaces to bridge */
505
	foreach ($members as $member) {
506
		if (!array_key_exists($member, $checklist))
507
			continue;
508
		$realif1 = get_real_interface($member);
509
		$realif =  escapeshellarg($realif1);
510
		if (!$realif) {
511
			log_error(gettext("realif not defined in interfaces bridge - up"));
512
			continue;
513
		}
514
		/* make sure the parent interface is up */
515
		pfSense_interface_mtu($realif1, $smallermtu);
516
		pfSense_interface_capabilities($realif1, -$flags);
517
		interfaces_bring_up($realif1);
518
		pfSense_bridge_add_member($bridgeif, $realif1);
519
	}
520

    
521
	if (isset($bridge['enablestp'])) {
522
		/* Choose spanning tree proto */
523
		mwexec("/sbin/ifconfig {$bridgeif} proto {$bridge['proto']}");	
524
		
525
		if (!empty($bridge['stp'])) {
526
			$stpifs = explode(',', $bridge['stp']);
527
			foreach ($stpifs as $stpif) {
528
				$realif = get_real_interface($stpif);
529
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
530
			}
531
		}
532
		if (!empty($bridge['maxage']))
533
			mwexec("/sbin/ifconfig {$bridgeif} maxage {$bridge['maxage']}");
534
		if (!empty($bridge['fwdelay']))
535
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay {$bridge['fwdelay']}");
536
		if (!empty($bridge['hellotime']))
537
                        mwexec("/sbin/ifconfig {$bridgeif} hellotime {$bridge['hellotime']}");
538
		if (!empty($bridge['priority']))
539
                        mwexec("/sbin/ifconfig {$bridgeif} priority {$bridge['priority']}");
540
		if (!empty($bridge['holdcount']))
541
                        mwexec("/sbin/ifconfig {$bridgeif} holdcnt {$bridge['holdcnt']}");
542
		if (!empty($bridge['ifpriority'])) {
543
			$pconfig = explode(",", $bridge['ifpriority']);
544
			$ifpriority = array();
545
			foreach ($pconfig as $cfg) {
546
				$embcfg = explode_assoc(":", $cfg);
547
				foreach ($embcfg as $key => $value)
548
					$ifpriority[$key] = $value;
549
			}
550
			foreach ($ifpriority as $key => $value) {
551
				$realif = get_real_interface($key);
552
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} {$value}"); 
553
			}
554
		}
555
		if (!empty($bridge['ifpathcost'])) {
556
			$pconfig = explode(",", $bridge['ifpathcost']);
557
			$ifpathcost = array();
558
			foreach ($pconfig as $cfg) {
559
				$embcfg = explode_assoc(":", $cfg);
560
				foreach ($embcfg as $key => $value)
561
					$ifpathcost[$key] = $value;
562
			}
563
			foreach ($ifpathcost as $key => $value) {
564
                        	$realif = get_real_interface($key);
565
                        	mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} {$value}");
566
                	}
567
		}
568
	}
569

    
570
	if ($bridge['maxaddr'] <> "")
571
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr {$bridge['maxaddr']}");
572
        if ($bridge['timeout'] <> "")
573
                mwexec("/sbin/ifconfig {$bridgeif} timeout {$bridge['timeout']}");
574
        if ($bridge['span'] <> "") {
575
		$realif = get_real_interface($bridge['span']);
576
                mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
577
	}
578
	if (!empty($bridge['edge'])) {
579
        	$edgeifs = explode(',', $bridge['edge']);
580
        	foreach ($edgeifs as $edgeif) {
581
			$realif = get_real_interface($edgeif);
582
                	mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
583
        	}
584
	}
585
	if (!empty($bridge['autoedge'])) {
586
        	$edgeifs = explode(',', $bridge['autoedge']);
587
        	foreach ($edgeifs as $edgeif) {
588
                	$realif = get_real_interface($edgeif);
589
                	mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
590
        	}
591
	}
592
	if (!empty($bridge['ptp'])) {
593
        	$ptpifs = explode(',', $bridge['ptp']);
594
        	foreach ($ptpifs as $ptpif) {
595
                	$realif = get_real_interface($ptpif);
596
                	mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
597
        	}
598
	}
599
	if (!empty($bridge['autoptp'])) {
600
        	$ptpifs = explode(',', $bridge['autoptp']);
601
        	foreach ($ptpifs as $ptpif) {
602
                	$realif = get_real_interface($ptpif);
603
                	mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
604
        	}
605
	}
606
	if (!empty($bridge['static'])) {
607
        	$stickyifs = explode(',', $bridge['static']);
608
        	foreach ($stickyifs as $stickyif) {
609
                	$realif = get_real_interface($stickyif);
610
                	mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
611
        	}
612
	}
613
	if (!empty($bridge['private'])) {
614
        	$privateifs = explode(',', $bridge['private']);
615
        	foreach ($privateifs as $privateif) {
616
                	$realif = get_real_interface($privateif);
617
               	 	mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
618
        	}
619
	}
620

    
621
	if($bridgeif)
622
		interfaces_bring_up($bridgeif);	
623
	else 
624
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
625

    
626
	return $bridgeif;
627
}
628

    
629
function interface_bridge_add_member($bridgeif, $interface) {
630

    
631
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
632
		return;
633

    
634
	$mtu = get_interface_mtu($bridgeif);
635
	$mtum = get_interface_mtu($interface);
636
	
637
	if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
638
		pfSense_interface_mtu($interface, $mtu);
639

    
640
	$options = pfSense_get_interface_addresses($bridgeif);
641
	$flags = 0;
642
	if (!isset($options['encaps']['txcsum']))
643
		$flags |= IFCAP_TXCSUM;
644

    
645
	if (!isset($options['encaps']['rxcsum']))
646
		$flags |= IFCAP_RXCSUM;
647

    
648
	pfSense_interface_capabilities($interface, -$flags);
649

    
650
	interfaces_bring_up($interface);
651
	pfSense_bridge_add_member($bridgeif, $interface);
652
}
653

    
654
function interfaces_lagg_configure() 
655
{
656
        global $config, $g;
657
		if($g['booting']) 
658
			echo gettext("Configuring LAGG interfaces...");
659
        $i = 0;
660
		if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
661
			foreach ($config['laggs']['lagg'] as $lagg) {
662
				if(empty($lagg['laggif']))
663
					$lagg['laggif'] = "lagg{$i}";
664
				/* XXX: Maybe we should report any errors?! */
665
				interface_lagg_configure($lagg);
666
				$i++;
667
			}
668
		}
669
		if($g['booting']) 
670
			echo gettext("done.") . "\n";
671
}
672

    
673
function interface_lagg_configure(&$lagg) {
674
        global $config, $g;
675

    
676
        if (!is_array($lagg))
677
		return -1;
678

    
679
	$members = explode(',', $lagg['members']);
680
	if (!count($members))
681
		return -1;
682
	
683
	if ($g['booting'] || !(empty($lagg['laggif']))) {
684
		pfSense_interface_destroy($lagg['laggif']);
685
		pfSense_interface_create($lagg['laggif']);
686
                $laggif = $lagg['laggif'];
687
        } else
688
		$laggif = pfSense_interface_create("lagg");
689

    
690
	/* Calculate smaller mtu and enforce it */
691
        $smallermtu = 0;
692
        foreach ($members as $member) {
693
		$opts = pfSense_get_interface_addresses($member);
694
                $mtu = $opts['mtu'];
695
		if (!isset($opts['encaps']['txcsum']))
696
                        $commontx = false;
697
                if (!isset($opts['encaps']['rxcsum']))
698
                        $commonrx = false;
699
		if (!isset($opts['encaps']['tso4']))
700
			$commontso4 = false;
701
		if (!isset($opts['encaps']['tso6']))
702
			$commontso6 = false;
703
		if (!isset($opts['encaps']['lro']))
704
			$commonlro = false;
705
		if ($smallermtu == 0 && !empty($mtu))
706
			$smallermtu = $mtu;
707
                else if (!empty($mtu) && $mtu < $smallermtu)
708
                        $smallermtu = $mtu;
709
        }
710

    
711
	/* Just in case anything is not working well */
712
        if ($smallermtu == 0)
713
                $smallermtu = 1500;
714

    
715
	$flags = 0;
716
        if ($commonrx === false)
717
                $flags |= IFCAP_RXCSUM;
718
        if ($commontx === false)
719
                $flags |= IFCAP_TXCSUM;
720
	if ($commontso4 === false)
721
                $flags |= IFCAP_TSO4;
722
        if ($commontso6 === false)
723
                $flags |= IFCAP_TSO6;
724
        if ($commonlro === false)
725
                $flags |= IFCAP_LRO;
726

    
727
	$checklist = get_interface_list();
728

    
729
	foreach ($members as $member) {
730
		if (!array_key_exists($member, $checklist))
731
			continue;
732
		/* make sure the parent interface is up */
733
		pfSense_interface_mtu($member, $smallermtu);
734
		pfSense_interface_capabilities($member, -$flags);
735
		interfaces_bring_up($member);
736
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
737
	}
738
	
739
	mwexec("/sbin/ifconfig {$laggif} laggproto {$lagg['proto']}");
740

    
741
	interfaces_bring_up($laggif);
742

    
743
	return $laggif;
744
}
745

    
746
function interfaces_gre_configure($checkparent = 0) {
747
        global $config;
748

    
749
        if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
750
                foreach ($config['gres']['gre'] as $i => $gre) {
751
                        if(empty($gre['greif']))
752
                                $gre['greif'] = "gre{$i}";
753
			if ($checkparent == 1 && strstr($gre['if'], "_vip"))
754
				continue;
755
			if ($checkparent == 2 && !strstr($gre['if'], "_vip"))
756
				continue;
757
                        /* XXX: Maybe we should report any errors?! */
758
                        interface_gre_configure($gre);
759
                }
760
        }
761
}
762

    
763
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
764
function interface_gre_configure(&$gre, $grekey = "") {
765
        global $config, $g;
766

    
767
	if (!is_array($gre))
768
		return -1;
769

    
770
	$realif = get_real_interface($gre['if']);
771
	$realifip = get_interface_ip($gre['if']);
772

    
773
	/* make sure the parent interface is up */
774
	interfaces_bring_up($realif);
775

    
776
	if ($g['booting'] || !(empty($gre['greif']))) {
777
		pfSense_interface_destroy($gre['greif']);
778
		pfSense_interface_create($gre['greif']);
779
		$greif = $gre['greif'];
780
	} else
781
		$greif = pfSense_interface_create("gre");
782

    
783
	/* Do not change the order here for more see gre(4) NOTES section. */
784
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} {$gre['remote-addr']}");
785
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
786
		mwexec("/sbin/ifconfig {$greif} inet6 {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} prefixlen /{$gre['tunnel-remote-net']} ");
787
	} else {
788
		mwexec("/sbin/ifconfig {$greif} {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
789
	}
790
	if (isset($gre['link0']) && $gre['link0'])
791
		pfSense_interface_flags($greif, IFF_LINK0);
792
	if (isset($gre['link1']) && $gre['link1'])
793
		pfSense_interface_flags($greif, IFF_LINK1);
794
	if (isset($gre['link2']) && $gre['link2'])
795
		pfSense_interface_flags($greif, IFF_LINK2);
796

    
797
	if($greif)
798
		interfaces_bring_up($greif);
799
	else 
800
		log_error(gettext("Could not bring greif up -- variable not defined."));
801

    
802
	if (isset($gre['link1']) && $gre['link1'])
803
		mwexec("/sbin/route add {$gre['tunnel-remote-addr']}/{$gre['tunnel-remote-net']} {$gre['tunnel-local-addr']}");
804
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
805
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
806
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
807
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
808

    
809
	return $greif;
810
}
811

    
812
function interfaces_gif_configure($checkparent = 0) {
813
	global $config;
814

    
815
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
816
		foreach ($config['gifs']['gif'] as $i => $gif) {
817
			if(empty($gif['gifif']))
818
				$gre['gifif'] = "gif{$i}";
819
			if ($checkparent == 1 && strstr($gif['if'], "_vip"))
820
				continue;
821
			if ($checkparent == 2 && !strstr($gif['if'], "_vip"))
822
				continue;
823
			/* XXX: Maybe we should report any errors?! */
824
			interface_gif_configure($gif);
825
		}
826
	}
827
}
828

    
829
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
830
function interface_gif_configure(&$gif, $gifkey = "") {
831
	global $config, $g;
832

    
833
	if (!is_array($gif))
834
		return -1;
835

    
836
	$realif = get_real_interface($gif['if']);
837

    
838
	if(is_ipaddrv4($gif['remote-addr'])) {
839
		$realifip = get_interface_ip($gif['if']);
840
		$realifgw = get_interface_gateway($gif['if']);
841
	}
842
	if(is_ipaddrv6($gif['remote-addr'])) {
843
		$realifip = get_interface_ipv6($gif['if']);
844
		$realifgw = get_interface_gatewayv6($gif['if']);
845
	}
846
	/* make sure the parent interface is up */
847
	if($realif)
848
		interfaces_bring_up($realif);
849
	else 
850
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
851

    
852
	if ($g['booting'] || !(empty($gif['gifif']))) {
853
		pfSense_interface_destroy($gif['gifif']);
854
		pfSense_interface_create($gif['gifif']);
855
		$gifif = $gif['gifif'];
856
	} else
857
		$gifif = pfSense_interface_create("gif");
858

    
859
	/* Do not change the order here for more see gif(4) NOTES section. */
860
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} {$gif['remote-addr']}");
861
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
862
		mwexec("/sbin/ifconfig {$gifif} inet6 {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} prefixlen /{$gif['tunnel-remote-net']} ");
863
	} else {
864
		mwexec("/sbin/ifconfig {$gifif} {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
865
	}
866
	if (isset($gif['link0']) && $gif['link0'])
867
		pfSense_interface_flags($gifif, IFF_LINK0);
868
	if (isset($gif['link1']) && $gif['link1'])
869
		pfSense_interface_flags($gifif, IFF_LINK1);
870
	if($gifif)
871
		interfaces_bring_up($gifif);
872
	else
873
		log_error(gettext("could not bring gifif up -- variable not defined"));
874

    
875
	$iflist = get_configured_interface_list();
876
	foreach($iflist as $ifname) {
877
		if($config['interfaces'][$ifname]['if'] == $gifif) {
878
			if(get_interface_gateway($ifname)) {
879
				system_routing_configure($ifname);
880
				break;
881
			}
882
			if(get_interface_gateway_v6($ifname)) {
883
				system_routing_configure($ifname);
884
				break;
885
			}
886
		}
887
	}
888

    
889

    
890
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
891
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
892
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
893
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
894

    
895
        if (is_ipaddrv4($realifgw)) {
896
                mwexec("route change -host {$gif['remote-addr']} {$realifgw}");
897
        }
898
        if (is_ipaddrv6($realifgw)) {
899
                mwexec("route change -host -inet6 {$gif['remote-addr']} {$realifgw}");
900
        }
901

    
902
	return $gifif;
903
}
904

    
905
function interfaces_configure() {
906
	global $config, $g;
907

    
908
	if ($g['platform'] == 'jail')
909
		return;
910

    
911
	/* Set up our loopback interface */
912
	interfaces_loopback_configure();
913

    
914
	/* set up LAGG virtual interfaces */
915
	interfaces_lagg_configure();
916

    
917
	/* set up VLAN virtual interfaces */
918
	interfaces_vlan_configure();
919

    
920
	interfaces_qinq_configure();
921

    
922
	$iflist = get_configured_interface_with_descr();
923
	$delayed_list = array();
924
	$bridge_list = array();
925
	
926
	/* This is needed to speedup interfaces on bootup. */
927
	$reload = false;
928
	if (!$g['booting'])
929
		$reload = true;
930

    
931
	foreach($iflist as $if => $ifname) {
932
		$realif = $config['interfaces'][$if]['if'];
933
		if (strstr($realif, "bridge")) 
934
			$bridge_list[$if] = $ifname;
935
		else if (strstr($realif, "gre"))
936
			$delayed_list[$if] = $ifname;
937
		else if (strstr($realif, "gif"))
938
			$delayed_list[$if] = $ifname;
939
		else if (strstr($realif, "ovpn")) {
940
			//echo "Delaying OpenVPN interface configuration...done.\n";
941
			continue;
942
		} else {
943
			if ($g['booting'])
944
				printf(gettext("Configuring %s interface..."), $ifname);
945

    
946
			if($g['debug'])
947
				log_error(sprintf(gettext("Configuring %s"), $ifname));
948
			interface_configure($if, $reload);
949
			if ($g['booting']) 
950
				echo gettext( "done.") . "\n";
951
		}
952
	}
953

    
954
	/* create the unconfigured wireless clones */
955
	interfaces_create_wireless_clones();
956

    
957
	/*
958
	 * NOTE: The following function parameter consists of
959
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
960
	 *	2 - Do load gre/gif/bridge with parent/member as vip
961
	 */
962

    
963
	/* set up GRE virtual interfaces */
964
	interfaces_gre_configure(1);
965

    
966
	/* set up GIF virtual interfaces */
967
	interfaces_gif_configure(1);
968

    
969
	/* set up BRIDGe virtual interfaces */
970
	interfaces_bridge_configure(1);
971

    
972
	/* bring up vip interfaces */
973
	interfaces_vips_configure();
974

    
975
	/* set up GRE virtual interfaces */
976
	interfaces_gre_configure(2);
977

    
978
	/* set up GIF virtual interfaces */
979
	interfaces_gif_configure(2);
980

    
981
	foreach ($delayed_list as $if => $ifname) {
982
		if ($g['booting'])
983
			printf(gettext("Configuring %s interface..."), $ifname);
984
        	if ($g['debug'])
985
        		log_error(sprintf(gettext("Configuring %s"), $ifname));
986

    
987
		interface_configure($if, $reload);
988

    
989
		if ($g['booting'])
990
			echo gettext("done.") . "\n";
991
	}
992

    
993
	/* set up BRIDGe virtual interfaces */
994
	interfaces_bridge_configure(2);
995

    
996
	foreach ($bridge_list as $if => $ifname) {
997
		if ($g['booting'])
998
			printf(gettext("Configuring %s interface..."), $ifname);
999
		if($g['debug'])
1000
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1001

    
1002
		interface_configure($if, $reload);
1003

    
1004
		if ($g['booting'])
1005
			echo gettext("done.") . "\n";
1006
	}
1007

    
1008
	/* configure interface groups */
1009
	interfaces_group_setup();
1010

    
1011
	if (!$g['booting']) {
1012
		/* reconfigure static routes (kernel may have deleted them) */
1013
		system_routing_configure();
1014

    
1015
		/* reload IPsec tunnels */
1016
		vpn_ipsec_configure();
1017

    
1018
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1019
		services_dhcpd_configure();
1020

    
1021
		/* restart dnsmasq */
1022
		services_dnsmasq_configure();
1023

    
1024
		/* reload captive portal */
1025
		captiveportal_init_rules();
1026
	}
1027

    
1028
	return 0;
1029
}
1030

    
1031
function interface_reconfigure($interface = "wan", $reloadall = false) {
1032
	interface_bring_down($interface);
1033
	interface_configure($interface, $reloadall);
1034
}
1035

    
1036
function interface_vip_bring_down($vip) {
1037
	global $g;
1038

    
1039
	switch ($vip['mode']) {
1040
	case "proxyarp":
1041
		$vipif = get_real_interface($vip['interface']);
1042
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1043
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1044
		break;
1045
	case "ipalias":
1046
		$vipif = get_real_interface($vip['interface']);
1047
		if(does_interface_exist($vipif))
1048
			pfSense_interface_deladdress($vipif, $vip['subnet']);
1049
		break;
1050
	case "carp":
1051
		$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
1052
		if (does_interface_exist($vipif)) 
1053
			pfSense_interface_destroy($vipif);
1054
		break;
1055
	}
1056
}
1057

    
1058
function interface_bring_down($interface = "wan", $destroy = false) {
1059
	global $config, $g;
1060

    
1061
	if (!isset($config['interfaces'][$interface]))
1062
		return; 
1063
	log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1064

    
1065
	$ifcfg = $config['interfaces'][$interface];
1066

    
1067
	$realif = get_real_interface($interface);
1068

    
1069
	switch ($ifcfg['ipaddr']) {
1070
	case "ppp":
1071
	case "pppoe":
1072
	case "pptp":
1073
	case "l2tp":
1074
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1075
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1076
				if ($realif == $ppp['if']) {
1077
					if (isset($ppp['ondemand']) && !$destroy){
1078
						send_event("interface reconfigure {$interface}");
1079
						break;
1080
					}
1081
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1082
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1083
						sleep(2);
1084
					}
1085
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1086
					break;
1087
				}
1088
			}
1089
		}
1090
		break;
1091
	case "dhcp":
1092
		$pid = find_dhclient_process($realif);
1093
		if($pid)
1094
			mwexec("/bin/kill {$pid}");
1095
		sleep(1);
1096
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1097
		if(does_interface_exist("$realif")) {
1098
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1099
			if ($destroy == true)
1100
				pfSense_interface_flags($realif, -IFF_UP);
1101
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1102
		}
1103
		break;
1104
	default:
1105
		if(does_interface_exist("$realif")) {
1106
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1107
			if ($destroy == true)
1108
				pfSense_interface_flags($realif, -IFF_UP);
1109
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1110
		}
1111
		break;
1112
	}
1113

    
1114
	switch ($ifcfg['ipaddrv6']) {
1115
	case "slaac":
1116
	case "dhcp6":
1117
		$pidv6 = find_dhcp6c_process($realif);
1118
		if($pidv6)
1119
			mwexec("/bin/kill {$pidv6}");
1120
		sleep(3);
1121
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1122
		if(does_interface_exist("$realif")) {
1123
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1124
			if ($destroy == true)
1125
				pfSense_interface_flags($realif, -IFF_UP);
1126
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1127
		}
1128
		break;
1129
	case "6rd":
1130
		$realif = "srd0";
1131
		if(does_interface_exist("$realif")) {
1132
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1133
			if ($destroy == true)
1134
				pfSense_interface_flags($realif, -IFF_UP);
1135
		}		
1136
		break;
1137
	case "6to4":
1138
		$realif = "stf0";
1139
		if(does_interface_exist("$realif")) {
1140
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1141
			if ($destroy == true)
1142
				pfSense_interface_flags($realif, -IFF_UP);
1143
		}		
1144
		break;
1145
	default:
1146
		if(does_interface_exist("$realif")) {
1147
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1148
			if ($destroy == true)
1149
				pfSense_interface_flags($realif, -IFF_UP);
1150
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1151
		}
1152
		break;
1153
	}
1154

    
1155
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1156
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1157
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1158
	if (!empty($old_router)) {
1159
		log_error("Clearing states to old gateway {$old_router}.");
1160
		mwexec("/sbin/pfctl -b 0.0.0.0/32 -b {$old_router}/32");
1161
	}
1162

    
1163
	/* remove interface up file if it exists */
1164
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1165
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1166
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1167
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1168
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1169
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1170
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1171
	
1172
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1173
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1174
	if (is_array($ifcfg['wireless'])) {
1175
		mwexec(kill_hostapd($realif));
1176
		mwexec(kill_wpasupplicant($realif));
1177
	}
1178

    
1179
	if ($destroy == true) {
1180
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|^stf|^srd/i", $realif))
1181
			pfSense_interface_destroy($realif);
1182
	}	
1183

    
1184
	return;
1185
}
1186

    
1187
function interfaces_ptpid_used($ptpid) {
1188
	global $config;
1189

    
1190
	if (is_array($config['ppps']['ppp']))
1191
		foreach ($config['ppps']['ppp'] as & $settings)
1192
			if ($ptpid == $settings['ptpid'])
1193
				return true;
1194

    
1195
	return false;
1196
}
1197

    
1198
function interfaces_ptpid_next() {
1199

    
1200
	$ptpid = 0;
1201
	while(interfaces_ptpid_used($ptpid))
1202
		$ptpid++;
1203

    
1204
	return $ptpid;
1205
}
1206

    
1207
function getMPDCRONSettings($pppif_) {
1208
	global $config;
1209
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
1210
	if (is_array($config['cron']['item'])) {
1211
		for ($i = 0; $i < count($config['cron']['item']); $i++) {
1212
			$item = $config['cron']['item'][$i];
1213
			if (strpos($item['command'], $cron_cmd_file.$pppif_) !== false) {
1214
				return array("ID" => $i, "ITEM" => $item);
1215
			}
1216
		}
1217
	}
1218
	return NULL;
1219
}
1220

    
1221
function handle_pppoe_reset($post_array) {
1222
	global $config, $g;
1223

    
1224
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
1225

    
1226
	$pppif = $post_array['type'].$post_array['ptpid'];
1227
	if (!is_array($config['cron']['item'])) 
1228
		$config['cron']['item'] = array(); 
1229
	$itemhash = getMPDCRONSettings($pppif);
1230
	$item = $itemhash['ITEM'];
1231
	
1232
	// reset cron items if necessary and return
1233
	if (empty($post_array['pppoe-reset-type'])) {
1234
		if (isset($item))
1235
			unset($config['cron']['item'][$itemhash['ID']]);
1236
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1237
		return;
1238
	}
1239

    
1240
	if (empty($item)) 
1241
		$item = array();
1242
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1243
		$item['minute'] = $post_array['pppoe_resetminute'];
1244
		$item['hour'] = $post_array['pppoe_resethour'];
1245
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1246
			$date = explode("/", $post_array['pppoe_resetdate']);
1247
			$item['mday'] = $date[1];
1248
			$item['month'] = $date[0];
1249
		} else {
1250
			$item['mday'] = "*";
1251
			$item['month'] = "*";
1252
		}
1253
		$item['wday'] = "*";
1254
		$item['who'] = "root";
1255
		$item['command'] = $cron_cmd_file.$pppif;
1256
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1257
		switch ($post_array['pppoe_pr_preset_val']) {
1258
			case "monthly":
1259
				$item['minute'] = "0";
1260
				$item['hour'] = "0";
1261
				$item['mday'] = "1";
1262
				$item['month'] = "*";
1263
				$item['wday'] = "*";
1264
				$item['who'] = "root";
1265
				$item['command'] = $cron_cmd_file.$pppif;
1266
				break;
1267
	        case "weekly":
1268
				$item['minute'] = "0";
1269
				$item['hour'] = "0";
1270
				$item['mday'] = "*";
1271
				$item['month'] = "*";
1272
				$item['wday'] = "0";
1273
				$item['who'] = "root";
1274
				$item['command'] = $cron_cmd_file.$pppif;
1275
				break;
1276
			case "daily":
1277
				$item['minute'] = "0";
1278
				$item['hour'] = "0";
1279
				$item['mday'] = "*";
1280
				$item['month'] = "*";
1281
				$item['wday'] = "*";
1282
				$item['who'] = "root";
1283
				$item['command'] = $cron_cmd_file.$pppif;
1284
				break;
1285
			case "hourly":
1286
				$item['minute'] = "0";
1287
				$item['hour'] = "*";
1288
				$item['mday'] = "*";
1289
				$item['month'] = "*";
1290
				$item['wday'] = "*";
1291
				$item['who'] = "root";
1292
				$item['command'] = $cron_cmd_file.$pppif;
1293
				break;
1294
		} // end switch
1295
	} else {
1296
		/* test whether a cron item exists and unset() it if necessary */
1297
		$itemhash = getMPDCRONSettings($pppif);
1298
		$item = $itemhash['ITEM'];
1299
		if (isset($item))
1300
			unset($config['cron']['item'][$itemhash['ID']]); 
1301
	}// end if
1302
	if (isset($itemhash['ID'])) 
1303
		$config['cron']['item'][$itemhash['ID']] = $item;
1304
	else 
1305
		$config['cron']['item'][] = $item;
1306
}
1307

    
1308
/*	This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1309
*	It writes the mpd config file to /var/etc every time the link is opened.
1310
*/
1311

    
1312
function interface_ppps_configure($interface) {
1313
	global $config, $g;
1314

    
1315
	/* Return for unassigned interfaces. This is a minimum requirement. */
1316
	if (empty($config['interfaces'][$interface]))
1317
		return 0;
1318
	$ifcfg = $config['interfaces'][$interface];
1319
	if (!isset($ifcfg['enable']))
1320
		return 0;
1321

    
1322
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1323
	if(!is_dir("/var/spool/lock")) {
1324
		exec("/bin/mkdir -p /var/spool/lock");
1325
		exec("/bin/chmod a+rw /var/spool/lock/.");
1326
	}
1327
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1328
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1329
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1330

    
1331
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1332
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1333
			if ($ifcfg['if'] == $ppp['if'])
1334
				break;
1335
		}
1336
	}
1337
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1338
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1339
		return 0;
1340
	}
1341
	$pppif = $ifcfg['if'];
1342
	if ($ppp['type'] == "ppp")
1343
		$type = "modem";
1344
	else
1345
		$type = $ppp['type'];
1346
	$upper_type = strtoupper($ppp['type']);	
1347

    
1348
	if($g['booting']) {
1349
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1350
		echo "starting {$pppif} link...";
1351
		// Do not re-configure the interface if we are booting and it's already been started
1352
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1353
			return 0;
1354
	}
1355

    
1356
	$ports = explode(',',$ppp['ports']);
1357
	if ($type != "modem") {
1358
		foreach ($ports as $pid => $port)
1359
			$ports[$pid] = get_real_interface($port);
1360
	}
1361
	$localips = explode(',',$ppp['localip']);
1362
	$gateways = explode(',',$ppp['gateway']);
1363
	$subnets = explode(',',$ppp['subnet']);
1364

    
1365
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1366
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1367
	 */
1368
	foreach($ports as $pid => $port){
1369
		switch ($ppp['type']) {
1370
			case "pppoe": 
1371
				/* Bring the parent interface up */
1372
				interfaces_bring_up($port);
1373
				pfSense_ngctl_attach(".", $port);
1374
				break;
1375
			case "pptp":
1376
			case "l2tp":
1377
				/* configure interface */
1378
				if(is_ipaddr($localips[$pid])){
1379
					// Manually configure interface IP/subnet
1380
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1381
					interfaces_bring_up($port);
1382
				} else if (empty($localips[$pid]))
1383
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1384
				
1385
				if(!is_ipaddr($localips[$pid])){
1386
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
1387
					$localips[$pid] = "0.0.0.0";
1388
				}
1389
				/* XXX: This needs to go away soon! [It's commented out!] */
1390
				/* Configure the gateway (remote IP ) */
1391
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1392
					/* XXX: Fix later 
1393
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1394
					if(!is_ipaddr($gateways[$pid])) {
1395
						log_error("Could not get a valid Gateway IP from {$port} via DNS in interfaces_ppps_configure.");
1396
						return 0;
1397
					}
1398
					*/
1399
				}
1400
				if(!is_ipaddr($gateways[$pid])){
1401
					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));
1402
					return 0;
1403
				}
1404
				pfSense_ngctl_attach(".", $port);
1405
				break;
1406
			case "ppp":
1407
				if (!file_exists("{$port}")) {
1408
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1409
					return 0;
1410
				}
1411
				break;
1412
			default:
1413
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1414
				break;
1415
		}
1416
	}
1417
	
1418
	if (is_array($ports) && count($ports) > 1)
1419
		$multilink = "enable";
1420
	else
1421
		$multilink = "disable";
1422
	
1423
	if ($type == "modem"){
1424
		if (is_ipaddr($ppp['localip']))
1425
			$localip = $ppp['localip'];
1426
		else
1427
			$localip = '0.0.0.0';
1428

    
1429
		if (is_ipaddr($ppp['gateway']))
1430
			$gateway = $ppp['gateway'];
1431
		else
1432
			$gateway = "10.64.64.{$pppid}";
1433
		$ranges = "{$localip}/0 {$gateway}/0";
1434
		
1435
		if (empty($ppp['apnum']))	
1436
			$ppp['apnum'] = 1;
1437
	} else
1438
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1439

    
1440
	if (isset($ppp['ondemand'])) 
1441
		$ondemand = "enable";
1442
	else
1443
		$ondemand = "disable";
1444
	if (!isset($ppp['idletimeout']))
1445
		$ppp['idletimeout'] = 0;
1446

    
1447
	if (empty($ppp['username']) && $type == "modem"){
1448
		$ppp['username'] = "user";
1449
		$ppp['password'] = "none";
1450
	}
1451
	if (empty($ppp['password']) && $type == "modem")
1452
		$passwd = "none";
1453
	else
1454
		$passwd = base64_decode($ppp['password']);
1455

    
1456
	$bandwidths = explode(',',$ppp['bandwidth']);
1457
	$defaultmtu = "1492";
1458
	if (!empty($ifcfg['mtu']))
1459
		$defaultmtu = intval($ifcfg['mtu']);
1460
	$mtus = explode(',',$ppp['mtu']);
1461
	$mrus = explode(',',$ppp['mru']);
1462

    
1463
	if (isset($ppp['mrru']))
1464
		$mrrus = explode(',',$ppp['mrru']);
1465

    
1466
	// Construct the mpd.conf file
1467
	$mpdconf = <<<EOD
1468
startup:
1469
	# configure the console
1470
	set console close
1471
	# configure the web server
1472
	set web close
1473

    
1474
default:
1475
{$ppp['type']}client:
1476
	create bundle static {$interface}
1477
	set bundle enable ipv6cp
1478
	set iface name {$pppif}
1479

    
1480
EOD;
1481
	$setdefaultgw = false;
1482
	$founddefaultgw = false;
1483
	if (is_array($config['gateways']['gateway_item'])) {
1484
		foreach($config['gateways']['gateway_item'] as $gateway) {
1485
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1486
				$setdefaultgw = true;
1487
				break;
1488
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1489
				$founddefaultgw = true;
1490
				break;
1491
			}
1492
		}
1493
	}
1494
	
1495
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1496
		$setdefaultgw = true;
1497
		$mpdconf .= <<<EOD
1498
	set iface route default
1499

    
1500
EOD;
1501
	}
1502
	$mpdconf .= <<<EOD
1503
	set iface {$ondemand} on-demand
1504
	set iface idle {$ppp['idletimeout']}
1505

    
1506
EOD;
1507

    
1508
	if (isset($ppp['ondemand']))
1509
		$mpdconf .= <<<EOD
1510
	set iface addrs 10.10.1.1 10.10.1.2
1511

    
1512
EOD;
1513
	
1514
	if (isset($ppp['tcpmssfix']))
1515
		$tcpmss = "disable";
1516
	else
1517
		$tcpmss = "enable";
1518
		$mpdconf .= <<<EOD
1519
	set iface {$tcpmss} tcpmssfix
1520

    
1521
EOD;
1522

    
1523
	$mpdconf .= <<<EOD
1524
	set iface up-script /usr/local/sbin/ppp-linkup
1525
	set iface down-script /usr/local/sbin/ppp-linkdown
1526
	set ipcp ranges {$ranges}
1527

    
1528
EOD;
1529
	if (isset($ppp['vjcomp']))
1530
		$mpdconf .= <<<EOD
1531
	set ipcp no vjcomp
1532

    
1533
EOD;
1534

    
1535
	if (isset($config['system']['dnsallowoverride']))
1536
		$mpdconf .= <<<EOD
1537
	set ipcp enable req-pri-dns
1538
	set ipcp enable req-sec-dns
1539

    
1540
EOD;
1541
	if (!isset($ppp['verbose_log']))
1542
		$mpdconf .= <<<EOD
1543
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1544

    
1545
EOD;
1546
	foreach($ports as $pid => $port){
1547
		$port = get_real_interface($port);
1548
		$mpdconf .= <<<EOD
1549

    
1550
	create link static {$interface}_link{$pid} {$type}
1551
	set link action bundle {$interface}
1552
	set link {$multilink} multilink
1553
	set link keep-alive 10 60
1554
	set link max-redial 0
1555

    
1556
EOD;
1557
		if (isset($ppp['shortseq']))
1558
			$mpdconf .= <<<EOD
1559
	set link no shortseq
1560

    
1561
EOD;
1562

    
1563
		if (isset($ppp['acfcomp']))
1564
			$mpdconf .= <<<EOD
1565
	set link no acfcomp
1566

    
1567
EOD;
1568

    
1569
		if (isset($ppp['protocomp']))
1570
			$mpdconf .= <<<EOD
1571
	set link no protocomp
1572

    
1573
EOD;
1574

    
1575
		$mpdconf .= <<<EOD
1576
	set link disable chap pap
1577
	set link accept chap pap eap
1578
	set link disable incoming
1579

    
1580
EOD;
1581

    
1582

    
1583
		if (!empty($bandwidths[$pid]))
1584
			$mpdconf .= <<<EOD
1585
	set link bandwidth {$bandwidths[$pid]}
1586

    
1587
EOD;
1588

    
1589
		if (empty($mtus[$pid]))
1590
			$mtus[$pid] = $defaultmtu;
1591
			$mpdconf .= <<<EOD
1592
	set link mtu {$mtus[$pid]}
1593

    
1594
EOD;
1595

    
1596
		if (!empty($mrus[$pid]))
1597
			$mpdconf .= <<<EOD
1598
	set link mru {$mrus[$pid]}
1599

    
1600
EOD;
1601

    
1602
		if (!empty($mrrus[$pid]))
1603
			$mpdconf .= <<<EOD
1604
	set link mrru {$mrrus[$pid]}
1605

    
1606
EOD;
1607

    
1608
		$mpdconf .= <<<EOD
1609
	set auth authname "{$ppp['username']}"
1610
	set auth password {$passwd}
1611

    
1612
EOD;
1613
		if ($type == "modem") {
1614
			$mpdconf .= <<<EOD
1615
	set modem device {$ppp['ports']}
1616
	set modem script DialPeer
1617
	set modem idle-script Ringback
1618
	set modem watch -cd
1619
	set modem var \$DialPrefix "DT"
1620
	set modem var \$Telephone "{$ppp['phone']}"
1621

    
1622
EOD;
1623
		}
1624
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1625
			$mpdconf .= <<<EOD
1626
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1627

    
1628
EOD;
1629
		}
1630
		if (isset($ppp['initstr']) && $type == "modem") {
1631
			$initstr = base64_decode($ppp['initstr']);
1632
			$mpdconf .= <<<EOD
1633
	set modem var \$InitString "{$initstr}"
1634

    
1635
EOD;
1636
		}
1637
		if (isset($ppp['simpin']) && $type == "modem") {
1638
			if($ppp['pin-wait'] == "")
1639
				$ppp['pin-wait'] = 0;
1640
			$mpdconf .= <<<EOD
1641
	set modem var \$SimPin "{$ppp['simpin']}"
1642
	set modem var \$PinWait "{$ppp['pin-wait']}"
1643

    
1644
EOD;
1645
		}
1646
		if (isset($ppp['apn']) && $type == "modem") {
1647
			$mpdconf .= <<<EOD
1648
	set modem var \$APN "{$ppp['apn']}"
1649
	set modem var \$APNum "{$ppp['apnum']}"
1650

    
1651
EOD;
1652
		}
1653
		if ($type == "pppoe") {
1654
			// Send a null service name if none is set.
1655
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1656
			$mpdconf .= <<<EOD
1657
	set pppoe service "{$provider}"
1658

    
1659
EOD;
1660
		}
1661
		if ($type == "pppoe")
1662
			$mpdconf .= <<<EOD
1663
	set pppoe iface {$port}
1664

    
1665
EOD;
1666

    
1667
		if ($type == "pptp" || $type == "l2tp") {
1668
			$mpdconf .= <<<EOD
1669
	set {$type} self {$localips[$pid]}
1670
	set {$type} peer {$gateways[$pid]}
1671

    
1672
EOD;
1673
		}
1674
		
1675
		$mpdconf .= "\topen\r\n";
1676
	} //end foreach($port)
1677

    
1678

    
1679
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1680
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1681
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1682
	else {
1683
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1684
		if (!$fd) {
1685
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1686
			return 0;
1687
		}
1688
		// Write out mpd_ppp.conf
1689
		fwrite($fd, $mpdconf);
1690
		fclose($fd);
1691
	}
1692

    
1693
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1694
	if (isset($ppp['uptime'])) {
1695
		if (!file_exists("/conf/{$pppif}.log")) {
1696
			conf_mount_rw();
1697
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1698
			conf_mount_ro();
1699
		}
1700
	} else {
1701
		if (file_exists("/conf/{$pppif}.log")) {
1702
			conf_mount_rw();
1703
			mwexec("rm -f /conf/{$pppif}.log");
1704
			conf_mount_ro();
1705
		}
1706
	}
1707

    
1708
	/* clean up old lock files */
1709
	foreach($ports as $port) {
1710
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1711
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1712
	}
1713

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

    
1717
	// Check for PPPoE periodic reset request 
1718
	if ($type == "pppoe") {
1719
		if (isset($ppp['pppoe-reset-type']))
1720
			setup_pppoe_reset_file($ppp['if'], $interface);
1721
		else
1722
			setup_pppoe_reset_file($ppp['if']);
1723
	}
1724
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1725
	$i = 0;
1726
	while($i < 10) {
1727
		exec("/sbin/ifconfig {$ppp['if']} 2>&1", $out, $ret);
1728
		if($ret == 0)
1729
			break;
1730
		sleep(1);
1731
		$i++;
1732
	}
1733

    
1734
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1735
	/* We should be able to launch the right version for each modem */
1736
	/* We can also guess the mondev from the manufacturer */
1737
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1738
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1739
	foreach($ports as $port) {
1740
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1741
			$mondev  = substr(basename($port), 0, -1);
1742
			$devlist = glob("/dev/{$mondev}?");
1743
			$mondev = basename(end($devlist));
1744
		}
1745
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1746
			$mondev  = substr(basename($port), 0, -1) . "1";
1747
		}
1748
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1749
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1750
	}
1751

    
1752
	return 1;
1753
}
1754

    
1755
function interfaces_carp_setup() {
1756
	global $g, $config;
1757

    
1758
	$balanacing = "";
1759
	$pfsyncinterface = "";
1760
	$pfsyncenabled = "";
1761
	if(isset($config['system']['developerspew'])) {
1762
		$mt = microtime();
1763
		echo "interfaces_carp_setup() being called $mt\n";
1764
	}
1765

    
1766
	// Prepare CmdCHAIN that will be used to execute commands.
1767
	$cmdchain = new CmdCHAIN();	
1768

    
1769
	if ($g['booting']) {
1770
		echo gettext("Configuring CARP settings...");
1771
		mute_kernel_msgs();
1772
	}
1773

    
1774
	/* suck in configuration items */
1775
	if($config['hasync']) {
1776
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1777
		$balanacing = $config['hasync']['balancing'];
1778
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1779
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1780
	} else {
1781
		unset($pfsyncinterface);
1782
		unset($balanacing);
1783
		unset($pfsyncenabled);
1784
	}
1785

    
1786
	if($balanacing) {
1787
		$cmdchain->add(gettext("Enable CARP ARP-balancing"), "/sbin/sysctl net.inet.carp.arpbalance=1", true);
1788
		$cmdchain->add(gettext("Disallow CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=0", true);
1789
	} else
1790
		$cmdchain->add(gettext("Enable CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=1", true);		
1791

    
1792
	$cmdchain->add(gettext("Enable CARP logging"), "/sbin/sysctl net.inet.carp.log=1", true);
1793
	if (!empty($pfsyncinterface))
1794
		$carp_sync_int = get_real_interface($pfsyncinterface);
1795

    
1796
	if($g['booting']) {
1797
		/*    install rules to alllow pfsync to sync up during boot
1798
		 *    carp interfaces will remain down until the bootup sequence finishes
1799
		 */
1800
		$fd = fopen("{$g['tmp_path']}/rules.boot", "w");
1801
		if ($fd) {
1802
			fwrite($fd, "block quick proto carp \n");
1803
			fwrite($fd, "block quick proto pfsync \n");
1804
			fwrite($fd, "pass out quick from any to any keep state\n");
1805
			fclose($fd);
1806
			mwexec("/sbin/pfctl -f {$g['tmp_path']}/rules.boot");
1807
		} else
1808
			log_error(gettext("Could not create rules.boot file!"));
1809
	}
1810

    
1811
	/* setup pfsync interface */
1812
	if($carp_sync_int and $pfsyncenabled) {
1813
		if (is_ipaddr($pfsyncpeerip))
1814
			$cmdchain->add(gettext("Bring up pfsync0 syncpeer"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} syncpeer {$pfsyncpeerip} up", false);						
1815
		else
1816
			$cmdchain->add(gettext("Bring up pfsync0 syncdev"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} up", false);			
1817
	} else
1818
		$cmdchain->add(gettext("Bring up pfsync0"), "/sbin/ifconfig pfsync0 syncdev lo0 up", false);						
1819

    
1820
	sleep(1);
1821

    
1822
	/* 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
1823
	 * for existing sessions.
1824
	 */
1825
	if ($config['hasync']['pfsyncenabled'] === "on"){
1826
		echo "waiting for pfsync...";
1827
		$i = 0;
1828
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1829
			$i++;
1830
			sleep(1);
1831
		}
1832
		echo "pfsync done in $i seconds.\n";
1833
		echo "Configuring CARP settings finalize...";
1834
	}
1835

    
1836
	if($config['virtualip']['vip'])
1837
		$cmdchain->add(gettext("Allow CARP."), "/sbin/sysctl net.inet.carp.allow=1", true);				
1838
	else
1839
		$cmdchain->add(gettext("Disallow CARP."), "/sbin/sysctl net.inet.carp.allow=0", true);		
1840
	
1841
	if($g['debug'])
1842
		$cmdchain->setdebug(); // optional for verbose logging
1843

    
1844
	$cmdchain->execute();
1845
	$cmdchain->clear();
1846

    
1847
	if ($g['booting']) {
1848
		unmute_kernel_msgs();
1849
		echo gettext("done.") . "\n";
1850
	}
1851
}
1852

    
1853
function interface_proxyarp_configure($interface = "") {
1854
	global $config, $g;
1855
	if(isset($config['system']['developerspew'])) {
1856
		$mt = microtime();
1857
		echo "interface_proxyarp_configure() being called $mt\n";
1858
	}
1859

    
1860
	/* kill any running choparp */
1861
	if (empty($interface))
1862
		killbyname("choparp");
1863
	else {
1864
		$vipif = get_real_interface($interface);
1865
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1866
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1867
	}
1868

    
1869
	$paa = array();
1870
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1871

    
1872
		/* group by interface */
1873
		foreach ($config['virtualip']['vip'] as $vipent) {
1874
			if ($vipent['mode'] === "proxyarp") {
1875
				if ($vipent['interface'])
1876
					$proxyif = $vipent['interface'];
1877
				else
1878
					$proxyif = "wan";
1879
				
1880
				if (!empty($interface) && $interface != $proxyif)
1881
					continue;
1882

    
1883
				if (!is_array($paa[$proxyif]))
1884
					$paa[$proxyif] = array();
1885

    
1886
				$paa[$proxyif][] = $vipent;
1887
			}
1888
		}
1889
	}
1890

    
1891
	if (!empty($interface)) {
1892
		if (is_array($paa[$interface])) {
1893
			$paaifip = get_interface_ip($interface);
1894
                        if (!is_ipaddr($paaifip))
1895
                                return;
1896
                        $args = get_real_interface($interface) . " auto";
1897
                        foreach ($paa[$interface] as $paent) {
1898
                                if (isset($paent['subnet']))
1899
                                        $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1900
                                else if (isset($paent['range']))
1901
                                        $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1902
                        }
1903
                        mwexec_bg("/usr/local/sbin/choparp " . $args);	
1904
		}
1905
	} else if (count($paa) > 0) {
1906
		foreach ($paa as $paif => $paents)  {
1907
			$paaifip = get_interface_ip($paif);
1908
			if (!is_ipaddr($paaifip))
1909
				continue;
1910
			$args = get_real_interface($paif) . " auto";
1911
			foreach ($paents as $paent) {
1912
				if (isset($paent['subnet']))
1913
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1914
				else if (isset($paent['range']))
1915
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1916
			}
1917
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1918
		}
1919
	}
1920
}
1921

    
1922
function interfaces_vips_configure($interface = "") {
1923
	global $g, $config;
1924
	if(isset($config['system']['developerspew'])) {
1925
		$mt = microtime();
1926
		echo "interfaces_vips_configure() being called $mt\n";
1927
	}
1928
	$paa = array();
1929
	if(is_array($config['virtualip']['vip'])) {
1930
		$carp_setuped = false;
1931
		$anyproxyarp = false;
1932
		foreach ($config['virtualip']['vip'] as $vip) {
1933
			switch ($vip['mode']) {
1934
			case "proxyarp":
1935
				/* nothing it is handled on interface_proxyarp_configure() */
1936
				if ($interface <> "" && $vip['interface'] <> $interface)
1937
					continue;
1938
				$anyproxyarp = true;
1939
				break;
1940
			case "ipalias":
1941
				if ($interface <> "" && $vip['interface'] <> $interface)
1942
					continue;
1943
				interface_ipalias_configure(&$vip);
1944
				break;
1945
			case "carp":
1946
				if ($interface <> "" && $vip['interface'] <> $interface)
1947
					continue;
1948
				if ($carp_setuped == false)
1949
					$carp_setuped = true;
1950
				interface_carp_configure($vip);
1951
				break;
1952
			}
1953
		}
1954
		if ($carp_setuped == true)
1955
			interfaces_carp_setup();
1956
		if ($anyproxyarp == true)
1957
			interface_proxyarp_configure();
1958
	}
1959
}
1960

    
1961
function interface_ipalias_configure(&$vip) {
1962
	if ($vip['mode'] == "ipalias") {
1963
		$if = get_real_interface($vip['interface']);
1964
		$af = "inet";
1965
		if(is_ipaddrv6($vip['subnet']))
1966
			$af = "inet6";
1967
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
1968
	}
1969
}
1970

    
1971
function interface_reload_carps($cif) {
1972
	global $config;
1973

    
1974
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
1975
	if (empty($carpifs))
1976
		return;
1977

    
1978
	$carps = explode(" ", $carpifs);
1979
	if(is_array($config['virtualip']['vip'])) {
1980
		$viparr = &$config['virtualip']['vip'];
1981
		foreach ($viparr as $vip) {
1982
			if (in_array($vip['carpif'], $carps)) {
1983
				switch ($vip['mode']) {
1984
				case "carp":
1985
					interface_vip_bring_down($vip);
1986
					sleep(1);
1987
					interface_carp_configure($vip);
1988
					break;
1989
				case "ipalias":
1990
					interface_vip_bring_down($vip);
1991
					sleep(1);
1992
					interface_ipalias_configure($vip);
1993
					break;
1994
				}
1995
			}
1996
		}
1997
	}
1998
}
1999

    
2000
function interface_carp_configure(&$vip) {
2001
	global $config, $g;
2002
	if(isset($config['system']['developerspew'])) {
2003
		$mt = microtime();
2004
		echo "interface_carp_configure() being called $mt\n";
2005
	}
2006

    
2007
	if ($vip['mode'] != "carp")
2008
		return;
2009

    
2010
	/*
2011
	 * ensure the interface containing the VIP really exists
2012
 	 * prevents a panic if the interface is missing or invalid
2013
	 */
2014
	$realif = get_real_interface($vip['interface']);
2015
	if (!does_interface_exist($realif)) {
2016
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2017
		return;
2018
	}
2019

    
2020
	if(is_ipaddrv4($vip['subnet'])) {
2021
		/* Ensure CARP IP really exists prior to loading up. */
2022
		$ww_subnet_ip = find_interface_ip($realif);
2023
		$ww_subnet_bits = find_interface_subnet($realif);
2024
		if (!ip_in_subnet($vip['subnet'], gen_subnet($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2025
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IP address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2026
			return;
2027
		}
2028
	}
2029
	if(is_ipaddrv6($vip['subnet'])) {
2030
		/* Ensure CARP IP really exists prior to loading up. */
2031
		$ww_subnet_ip = find_interface_ipv6($realif);
2032
		$ww_subnet_bits = find_interface_subnetv6($realif);
2033
		if (!ip_in_subnet($vip['subnet'], gen_subnetv6($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2034
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IPv6 address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2035
			return;
2036
		}
2037
	}
2038

    
2039
	// set the vip interface to the vhid
2040
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2041

    
2042
	/* create the carp interface and setup */
2043
	if (does_interface_exist($vipif)) {
2044
		pfSense_interface_flags($vipif, -IFF_UP);
2045
	} else {
2046
		$carpif = pfSense_interface_create("carp");
2047
		pfSense_interface_rename($carpif, $vipif);
2048
		pfSense_ngctl_name("{$carpif}:", $vipif);
2049
	}
2050

    
2051
	/* invalidate interface cache */
2052
	get_interface_arr(true);
2053

    
2054
	$vip_password = $vip['password'];
2055
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2056
	if ($vip['password'] != "")
2057
		$password = " pass {$vip_password}";
2058

    
2059
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2060
	$advbase = "";
2061
	if (!empty($vip['advbase']))
2062
		$advbase = "advbase {$vip['advbase']}";
2063

    
2064
	if(is_ipaddrv4($vip['subnet'])) {
2065
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2066
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2067
	}
2068
	if(is_ipaddrv6($vip['subnet'])) {
2069
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2070
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2071
	}
2072

    
2073
	interfaces_bring_up($vipif);
2074

    
2075
	return $vipif;
2076
}
2077

    
2078
function interface_wireless_clone($realif, $wlcfg) {
2079
	global $config, $g;
2080
	/*   Check to see if interface has been cloned as of yet.  
2081
	 *   If it has not been cloned then go ahead and clone it.
2082
	 */
2083
	$needs_clone = false;
2084
	if(is_array($wlcfg['wireless']))
2085
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2086
	else
2087
		$wlcfg_mode = $wlcfg['mode'];
2088
	switch($wlcfg_mode) {
2089
		 case "hostap":
2090
			$mode = "wlanmode hostap";
2091
			break;
2092
		 case "adhoc":
2093
			$mode = "wlanmode adhoc";
2094
			break;
2095
		 default:
2096
			$mode = "";
2097
			break;
2098
	}
2099
	$baseif = interface_get_wireless_base($wlcfg['if']);
2100
	if(does_interface_exist($realif)) {
2101
		exec("/sbin/ifconfig {$realif}", $output, $ret);
2102
		$ifconfig_str = implode($output);
2103
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2104
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2105
			$needs_clone = true;
2106
		}
2107
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2108
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2109
			$needs_clone = true;
2110
		}
2111
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2112
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2113
			$needs_clone = true;
2114
		}
2115
	} else {
2116
		$needs_clone = true;
2117
	}
2118

    
2119
	if($needs_clone == true) {
2120
		/* remove previous instance if it exists */
2121
		if(does_interface_exist($realif))
2122
			pfSense_interface_destroy($realif);
2123

    
2124
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2125
		// Create the new wlan interface. FreeBSD returns the new interface name.
2126
		// example:  wlan2
2127
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2128
		if($ret <> 0) {
2129
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2130
			return false;
2131
		}
2132
		$newif = trim($out[0]);
2133
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2134
		pfSense_interface_rename($newif, $realif);
2135
		// FIXME: not sure what ngctl is for. Doesn't work.
2136
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2137
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2138
	}
2139
	return true;
2140
}
2141

    
2142
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2143
	global $config, $g;
2144

    
2145
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2146
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
2147
	                         'regdomain', 'regcountry', 'reglocation');
2148

    
2149
	if(!is_interface_wireless($ifcfg['if']))
2150
		return;
2151

    
2152
	$baseif = interface_get_wireless_base($ifcfg['if']);
2153

    
2154
	// Sync shared settings for assigned clones
2155
	$iflist = get_configured_interface_list(false, true);
2156
	foreach ($iflist as $if) {
2157
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2158
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2159
				foreach ($shared_settings as $setting) {
2160
					if ($sync_changes) {
2161
						if (isset($ifcfg['wireless'][$setting]))
2162
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2163
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2164
							unset($config['interfaces'][$if]['wireless'][$setting]);
2165
					} else {
2166
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2167
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2168
						else if (isset($ifcfg['wireless'][$setting]))
2169
							unset($ifcfg['wireless'][$setting]);
2170
					}
2171
				}
2172
				if (!$sync_changes)
2173
					break;
2174
			}
2175
		}
2176
	}
2177

    
2178
	// Read or write settings at shared area
2179
	if (isset($config['wireless']['interfaces'][$baseif])) {
2180
		foreach ($shared_settings as $setting) {
2181
			if ($sync_changes) {
2182
				if (isset($ifcfg['wireless'][$setting]))
2183
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2184
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2185
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2186
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2187
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2188
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2189
				else if (isset($ifcfg['wireless'][$setting]))
2190
					unset($ifcfg['wireless'][$setting]);
2191
			}
2192
		}
2193
	}
2194

    
2195
	// Sync the mode on the clone creation page with the configured mode on the interface
2196
	if (interface_is_wireless_clone($ifcfg['if'])) {
2197
		foreach ($config['wireless']['clone'] as &$clone) {
2198
			if ($clone['cloneif'] == $ifcfg['if']) {
2199
				if ($sync_changes) {
2200
					$clone['mode'] = $ifcfg['wireless']['mode'];
2201
				} else {
2202
					$ifcfg['wireless']['mode'] = $clone['mode'];
2203
				}
2204
				break;
2205
			}
2206
		}
2207
		unset($clone);
2208
	}
2209
}
2210

    
2211
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2212
	global $config, $g;
2213

    
2214
	/*    open up a shell script that will be used to output the commands.
2215
	 *    since wireless is changing a lot, these series of commands are fragile
2216
	 *    and will sometimes need to be verified by a operator by executing the command
2217
	 *    and returning the output of the command to the developers for inspection.  please
2218
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2219
	 */
2220

    
2221
	// Remove script file
2222
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2223

    
2224
	// Clone wireless nic if needed.
2225
	interface_wireless_clone($if, $wl);
2226

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

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

    
2234
	/* set values for /path/program */
2235
	$hostapd = "/usr/sbin/hostapd";
2236
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2237
	$ifconfig = "/sbin/ifconfig";
2238
	$sysctl = "/sbin/sysctl";
2239
	$killall = "/usr/bin/killall";
2240

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

    
2243
	$wlcmd = array();
2244
	$wl_sysctl = array();
2245
	/* Make sure it's up */
2246
	$wlcmd[] = "up";
2247
	/* Set a/b/g standard */
2248
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2249
	$wlcmd[] = "mode " . escapeshellarg($standard);
2250

    
2251
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2252
	 * to prevent massive packet loss under certain conditions. */
2253
	if(preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na"))
2254
		$wlcmd[] = "-ampdu";
2255

    
2256
	/* Set ssid */
2257
	if($wlcfg['ssid'])
2258
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2259

    
2260
	/* Set 802.11g protection mode */
2261
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2262

    
2263
	/* set wireless channel value */
2264
	if(isset($wlcfg['channel'])) {
2265
		if($wlcfg['channel'] == "0") {
2266
			$wlcmd[] = "channel any";
2267
		} else {
2268
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2269
		}
2270
	}
2271

    
2272
	/* Set antenna diversity value */
2273
	if(isset($wlcfg['diversity']))
2274
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2275

    
2276
	/* Set txantenna value */
2277
	if(isset($wlcfg['txantenna']))
2278
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2279

    
2280
	/* Set rxantenna value */
2281
	if(isset($wlcfg['rxantenna']))
2282
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2283

    
2284
	/* set Distance value */
2285
	if($wlcfg['distance'])
2286
		$distance = escapeshellarg($wlcfg['distance']);
2287

    
2288
	/* Set wireless hostap mode */
2289
	if ($wlcfg['mode'] == "hostap") {
2290
		$wlcmd[] = "mediaopt hostap";
2291
	} else {
2292
		$wlcmd[] = "-mediaopt hostap";
2293
	}
2294

    
2295
	/* Set wireless adhoc mode */
2296
	if ($wlcfg['mode'] == "adhoc") {
2297
		$wlcmd[] = "mediaopt adhoc";
2298
	} else {
2299
		$wlcmd[] = "-mediaopt adhoc";
2300
	}
2301

    
2302
	/* Not neccesary to set BSS mode as this is default if adhoc and/or hostap is NOT set */
2303

    
2304
	/* handle hide ssid option */
2305
	if(isset($wlcfg['hidessid']['enable'])) {
2306
		$wlcmd[] = "hidessid";
2307
	} else {
2308
		$wlcmd[] = "-hidessid";
2309
	}
2310

    
2311
	/* handle pureg (802.11g) only option */
2312
	if(isset($wlcfg['pureg']['enable'])) {
2313
		$wlcmd[] = "mode 11g pureg";
2314
	} else {
2315
		$wlcmd[] = "-pureg";
2316
	}
2317

    
2318
	/* handle puren (802.11n) only option */
2319
	if(isset($wlcfg['puren']['enable'])) {
2320
		$wlcmd[] = "puren";
2321
	} else {
2322
		$wlcmd[] = "-puren";
2323
	}
2324

    
2325
	/* enable apbridge option */
2326
	if(isset($wlcfg['apbridge']['enable'])) {
2327
		$wlcmd[] = "apbridge";
2328
	} else {
2329
		$wlcmd[] = "-apbridge";
2330
	}
2331

    
2332
	/* handle turbo option */
2333
	if(isset($wlcfg['turbo']['enable'])) {
2334
		$wlcmd[] = "mediaopt turbo";
2335
	} else {
2336
		$wlcmd[] = "-mediaopt turbo";
2337
	}
2338

    
2339
	/* handle txpower setting */
2340
	/* if($wlcfg['txpower'] <> "")
2341
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2342
	*/
2343
	/* handle wme option */
2344
	if(isset($wlcfg['wme']['enable'])) {
2345
		$wlcmd[] = "wme";
2346
	} else {
2347
		$wlcmd[] = "-wme";
2348
	}
2349

    
2350
	/* set up wep if enabled */
2351
	$wepset = "";
2352
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2353
		switch($wlcfg['wpa']['auth_algs']) {
2354
			case "1":
2355
				$wepset .= "authmode open wepmode on ";
2356
				break;
2357
			case "2":
2358
				$wepset .= "authmode shared wepmode on ";
2359
				break;
2360
			case "3":
2361
				$wepset .= "authmode mixed wepmode on ";
2362
		}
2363
		$i = 1;
2364
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2365
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2366
			if (isset($wepkey['txkey'])) {
2367
				$wlcmd[] = "weptxkey {$i} ";
2368
			}
2369
			$i++;
2370
		}
2371
		$wlcmd[] = $wepset;
2372
	} else {
2373
		$wlcmd[] = "authmode open wepmode off ";
2374
	}
2375

    
2376
	mwexec(kill_hostapd("{$if}"));
2377
	mwexec(kill_wpasupplicant("{$if}"));
2378

    
2379
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2380
	conf_mount_rw();
2381

    
2382
	switch ($wlcfg['mode']) {
2383
		case 'bss':
2384
			if (isset($wlcfg['wpa']['enable'])) {
2385
				$wpa .= <<<EOD
2386
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2387
ctrl_interface_group=0
2388
ap_scan=1
2389
#fast_reauth=1
2390
network={
2391
ssid="{$wlcfg['ssid']}"
2392
scan_ssid=1
2393
priority=5
2394
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2395
psk="{$wlcfg['wpa']['passphrase']}"
2396
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2397
group={$wlcfg['wpa']['wpa_pairwise']}
2398
}
2399
EOD;
2400

    
2401
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2402
				fwrite($fd, "{$wpa}");
2403
				fclose($fd);
2404
			}
2405
			break;
2406
		case 'hostap':
2407
			if($wlcfg['wpa']['passphrase']) 
2408
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2409
			else 
2410
				$wpa_passphrase = "";
2411
			if (isset($wlcfg['wpa']['enable'])) {
2412
				$wpa .= <<<EOD
2413
interface={$if}
2414
driver=bsd
2415
logger_syslog=-1
2416
logger_syslog_level=0
2417
logger_stdout=-1
2418
logger_stdout_level=0
2419
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2420
ctrl_interface={$g['varrun_path']}/hostapd
2421
ctrl_interface_group=wheel
2422
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2423
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2424
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2425
ssid={$wlcfg['ssid']}
2426
debug={$wlcfg['wpa']['debug_mode']}
2427
auth_algs={$wlcfg['wpa']['auth_algs']}
2428
wpa={$wlcfg['wpa']['wpa_mode']}
2429
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2430
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2431
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2432
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2433
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2434
{$wpa_passphrase}
2435

    
2436
EOD;
2437

    
2438
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2439
	$wpa .= <<<EOD
2440
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2441
rsn_preauth=1
2442
rsn_preauth_interfaces={$if}
2443

    
2444
EOD;
2445

    
2446
}
2447
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2448
					$auth_server_port = "1812";
2449
					if($wlcfg['auth_server_port']) 
2450
						$auth_server_port = $wlcfg['auth_server_port'];
2451
					$auth_server_port2 = "1812";
2452
					if($wlcfg['auth_server_port2']) 
2453
						$auth_server_port2 = $wlcfg['auth_server_port2'];
2454
					$wpa .= <<<EOD
2455

    
2456
ieee8021x=1
2457
auth_server_addr={$wlcfg['auth_server_addr']}
2458
auth_server_port={$auth_server_port}
2459
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2460
auth_server_addr={$wlcfg['auth_server_addr2']}
2461
auth_server_port={$auth_server_port2}
2462
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2463

    
2464
EOD;
2465
				} else {
2466
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2467
				}
2468

    
2469
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2470
				fwrite($fd, "{$wpa}");
2471
				fclose($fd);
2472

    
2473
			}
2474
			break;
2475
	}
2476

    
2477
	/*
2478
	 *    all variables are set, lets start up everything
2479
	 */
2480

    
2481
	$baseif = interface_get_wireless_base($if);
2482
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2483
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2484

    
2485
	/* set sysctls for the wireless interface */
2486
	if (!empty($wl_sysctl)) {
2487
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2488
		foreach ($wl_sysctl as $wl_sysctl_line) {
2489
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2490
		}
2491
	}
2492

    
2493
	/* set ack timers according to users preference (if he/she has any) */
2494
	if($distance) {
2495
		fwrite($fd_set, "# Enable ATH distance settings\n");
2496
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2497
	}
2498

    
2499
	if (isset($wlcfg['wpa']['enable'])) {
2500
		if ($wlcfg['mode'] == "bss") {
2501
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2502
		}
2503
		if ($wlcfg['mode'] == "hostap") {
2504
			/* add line to script to restore old mac to make hostapd happy */
2505
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2506
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2507
				if (is_macaddr($if_oldmac))
2508
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2509
						" link " . escapeshellarg($if_oldmac) . "\n");
2510
			}
2511

    
2512
			fwrite($fd_set, "{$hostapd} -B {$g['varetc_path']}/hostapd_{$if}.conf\n");
2513

    
2514
			/* add line to script to restore spoofed mac after running hostapd */
2515
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2516
				if ($wl['spoofmac'])
2517
					$if_curmac = $wl['spoofmac'];
2518
				else
2519
					$if_curmac = get_interface_mac($if);
2520
				if (is_macaddr($if_curmac))
2521
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2522
						" link " . escapeshellarg($if_curmac) . "\n");
2523
			}
2524
		}
2525
	}
2526

    
2527
	fclose($fd_set);
2528
	conf_mount_ro();
2529

    
2530
	/* Making sure regulatory settings have actually changed
2531
	 * before applying, because changing them requires bringing
2532
	 * down all wireless networks on the interface. */
2533
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2534
	$ifconfig_str = implode($output);
2535
	unset($output);
2536
	$reg_changing = false;
2537

    
2538
	/* special case for the debug country code */
2539
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2540
		$reg_changing = true;
2541
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2542
		$reg_changing = true;
2543
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2544
		$reg_changing = true;
2545
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2546
		$reg_changing = true;
2547
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2548
		$reg_changing = true;
2549

    
2550
	if ($reg_changing) {
2551
		/* set regulatory domain */
2552
		if($wlcfg['regdomain'])
2553
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2554

    
2555
		/* set country */
2556
		if($wlcfg['regcountry'])
2557
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2558

    
2559
		/* set location */
2560
		if($wlcfg['reglocation'])
2561
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2562

    
2563
		$wlregcmd_args = implode(" ", $wlregcmd);
2564

    
2565
		/* build a complete list of the wireless clones for this interface */
2566
		$clone_list = array();
2567
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2568
			$clone_list[] = interface_get_wireless_clone($baseif);
2569
		if (is_array($config['wireless']['clone'])) {
2570
			foreach ($config['wireless']['clone'] as $clone) {
2571
				if ($clone['if'] == $baseif)
2572
					$clone_list[] = $clone['cloneif'];
2573
			}
2574
		}
2575

    
2576
		/* find which clones are up and bring them down */
2577
		$clones_up = array();
2578
		foreach ($clone_list as $clone_if) {
2579
			$clone_status = pfSense_get_interface_addresses($clone_if);
2580
			if ($clone_status['status'] == 'up') {
2581
				$clones_up[] = $clone_if;
2582
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2583
			}
2584
		}
2585

    
2586
		/* apply the regulatory settings */
2587
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2588

    
2589
		/* bring the clones back up that were previously up */
2590
		foreach ($clones_up as $clone_if) {
2591
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2592

    
2593
			/*
2594
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2595
			 * is in infrastructure mode, and WPA is enabled.
2596
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2597
			 */
2598
			if ($clone_if != $if) {
2599
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2600
				if ( !empty($friendly_if)
2601
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2602
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2603
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2604
				}
2605
			}
2606
		}
2607
	}
2608

    
2609
	/* The mode must be specified in a separate command before ifconfig
2610
	 * will allow the mode and channel at the same time in the next. */
2611
	mwexec("/sbin/ifconfig {$if} mode " . escapeshellarg($standard));
2612

    
2613
	/* configure wireless */
2614
	$wlcmd_args = implode(" ", $wlcmd);
2615
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2616

    
2617
	
2618
	sleep(1);
2619
	/* execute hostapd and wpa_supplicant if required in shell */
2620
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2621

    
2622
	return 0;
2623

    
2624
}
2625

    
2626
function kill_hostapd($interface) {
2627
	return "/bin/pkill -f \"hostapd .*{$interface}\"\n";
2628
}
2629

    
2630
function kill_wpasupplicant($interface) {
2631
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\"\n";
2632
}
2633

    
2634
function find_dhclient_process($interface) {
2635
	if ($interface)
2636
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2637
	else
2638
		$pid = 0;
2639

    
2640
	return intval($pid);
2641
}
2642

    
2643
function find_dhcp6c_process($interface) {
2644
	if ($interface)
2645
		$pid = `/bin/ps auxww|grep "[d]hclient[ ]-6" |grep "{$interface}"|awk '{print $2}'`;
2646
	else
2647
		return(false);
2648

    
2649
	return intval($pid);
2650
}
2651

    
2652
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2653
	global $config, $g;
2654
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2655
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2656

    
2657
	$wancfg = $config['interfaces'][$interface];
2658

    
2659
	$realif = get_real_interface($interface);
2660
	$realhwif_array = get_parent_interface($interface);
2661
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2662
	$realhwif = $realhwif_array[0];
2663

    
2664
	/* Disable Accepting router advertisements unless specifically requested */
2665
	log_error("Deny router advertisements for interface {$interface}");
2666
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2667
			
2668
	if (!$g['booting'] && !substr($realif, 0, 4) == "ovpn") {
2669
		/* remove all IPv4 and IPv6 addresses */
2670
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0);
2671
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -alias", true) == 0);
2672

    
2673
		/* only bring down the interface when both v4 and v6 are set to NONE */
2674
		if(($wancfg['ipaddr'] <> "none") && ($wancfg['ipaddrv6'] <> "none")) {
2675
			interface_bring_down($interface);
2676
		}
2677
	}
2678

    
2679
	/* wireless configuration? */
2680
	if (is_array($wancfg['wireless']))
2681
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2682

    
2683
	$mac = get_interface_mac($realhwif);
2684
	/*	Don't try to reapply the spoofed MAC if it's already applied.
2685
		When ifconfig link is used, it cycles the interface down/up, which triggers 
2686
		the interface config again, which attempts to spoof the MAC again, 
2687
		which cycles the link again... */
2688
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2689
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2690
			" link " . escapeshellarg($wancfg['spoofmac']));
2691

    
2692
                /*
2693
                 * All vlans need to spoof their parent mac address, too.  see
2694
                 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2695
                 */
2696
                if (is_array($config['vlans']['vlan'])) {
2697
                        foreach ($config['vlans']['vlan'] as $vlan) {
2698
                                if ($vlan['if'] == $realhwif)
2699
                                        mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2700
                                                " link " . escapeshellarg($wancfg['spoofmac']));
2701
                        }
2702
                }
2703
	}  else {
2704

    
2705
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2706
			/*   this is not a valid mac address.  generate a
2707
			 *   temporary mac address so the machine can get online.
2708
			 */
2709
			echo gettext("Generating new MAC address.");
2710
			$random_mac = generate_random_mac_address();
2711
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2712
				" link " . escapeshellarg($random_mac));
2713
			$wancfg['spoofmac'] = $random_mac;
2714
			write_config();
2715
			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");
2716
		}
2717
	}
2718

    
2719
	/* media */
2720
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2721
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2722
		if ($wancfg['media'])
2723
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2724
		if ($wancfg['mediaopt'])
2725
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2726
		mwexec($cmd);
2727
	}
2728
	if (!empty($wancfg['mtu']))
2729
		pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2730
	else {
2731
		$mtu = get_interface_default_mtu(remove_numbers($realhwif));
2732
		if ($mtu != get_interface_mtu($realhwif))
2733
			pfSense_interface_mtu($realhwif, $mtu);
2734
	}
2735

    
2736
	$options = pfSense_get_interface_addresses($realhwif);
2737
	if (is_array($options) && isset($options['caps']['polling'])) {
2738
		if (isset($config['system']['polling']))
2739
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2740
		else
2741
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2742
	}
2743

    
2744
	/* skip vlans for checksumming and polling */
2745
        if (!stristr($realhwif, "vlan") && is_array($options)) {
2746
		$flags = 0;
2747
		if(isset($config['system']['disablechecksumoffloading'])) {
2748
			if (isset($options['encaps']['txcsum']))
2749
				$flags |= IFCAP_TXCSUM;
2750
			if (isset($options['encaps']['rxcsum']))
2751
				$flags |= IFCAP_RXCSUM;
2752
        	} else {
2753
 			if (!isset($options['caps']['txcsum']))
2754
				$flags |= IFCAP_TXCSUM;
2755
			if (!isset($options['caps']['rxcsum']))
2756
				$flags |= IFCAP_RXCSUM;
2757
        	}
2758

    
2759
        	if(isset($config['system']['disablesegmentationoffloading'])) {
2760
                	if (isset($options['encaps']['tso4']))
2761
				$flags |= IFCAP_TSO;
2762
                	if (isset($options['encaps']['tso6']))
2763
				$flags |= IFCAP_TSO;
2764
        	} else {
2765
                	if (!isset($options['caps']['tso4']))
2766
				$flags |= IFCAP_TSO;
2767
                	if (!isset($options['caps']['tso6']))
2768
				$flags |= IFCAP_TSO;
2769
        	}
2770

    
2771
        	if(isset($config['system']['disablelargereceiveoffloading'])) {
2772
                	if (isset($options['encaps']['lro']))
2773
				$flags |= IFCAP_LRO;
2774
        	} else {
2775
                	if (!isset($options['caps']['lro']))
2776
				$flags |= IFCAP_LRO;
2777
        	}
2778

    
2779
        	/* if the NIC supports polling *AND* it is enabled in the GUI */
2780
        	if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2781
			$flags |= IFCAP_POLLING;
2782
		}
2783
               	pfSense_interface_capabilities($realhwif, -$flags);
2784
	}
2785

    
2786
	/* invalidate interface/ip/sn cache */
2787
	get_interface_arr(true);
2788
	unset($interface_ip_arr_cache[$realif]);
2789
	unset($interface_sn_arr_cache[$realif]);
2790
	unset($interface_ipv6_arr_cache[$realif]);
2791
	unset($interface_snv6_arr_cache[$realif]);
2792

    
2793
	switch ($wancfg['ipaddr']) {
2794
		case 'dhcp':
2795
			interface_dhcp_configure($interface);
2796
			break;
2797
		case 'pppoe':
2798
		case 'l2tp':
2799
		case 'pptp':
2800
		case 'ppp':
2801
			interface_ppps_configure($interface);
2802
			break;
2803
		default:
2804
			if (is_ipaddr($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
2805
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2806
			} else if (substr($realif, 0, 3) == "gre") {
2807
				if (is_array($config['gres']['gre'])) {
2808
					foreach ($config['gres']['gre'] as $gre)
2809
						if ($gre['greif'] == $realif)
2810
							interface_gre_configure($gre);
2811
				}
2812
			} else if (substr($realif, 0, 3) == "gif") {
2813
				 if (is_array($config['gifs']['gif'])) {
2814
					foreach ($config['gifs']['gif'] as $gif)
2815
						if($gif['gifif'] == $realif)
2816
							interface_gif_configure($gif);
2817
				}
2818
			} else if (substr($realif, 0, 4) == "ovpn") {
2819
				/* XXX: Should be done anything?! */
2820
			}
2821
			break;
2822
	}
2823

    
2824
	switch ($wancfg['ipaddrv6']) {
2825
		case 'slaac':
2826
		case 'dhcp6':
2827
			interface_dhcpv6_configure($interface);
2828
			break;
2829
		case '6rd':
2830
			interface_6rd_configure($interface);
2831
			break;
2832
		case '6to4':
2833
			interface_6to4_configure($interface);
2834
			break;
2835
		case 'track6':
2836
			interface_track6_configure($interface);
2837
			break;
2838
		default:
2839
			if (is_ipaddr($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
2840
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
2841
				// FIXME: Add IPv6 Support to the pfSense module
2842
				mwexec("/sbin/ifconfig {$realif} inet6 {$wancfg['ipaddrv6']} prefixlen {$wancfg['subnetv6']} ");
2843
			}
2844
			break;
2845
	}
2846

    
2847
	if(does_interface_exist($wancfg['if']))
2848
		interfaces_bring_up($wancfg['if']);
2849

    
2850
	interface_netgraph_needed($interface);
2851
 	
2852
	if (!$g['booting']) {
2853
		link_interface_to_vips($interface, "update");
2854

    
2855
		unset($gre);
2856
		$gre = link_interface_to_gre($interface);
2857
		if (!empty($gre))
2858
			array_walk($gre, 'interface_gre_configure');
2859

    
2860
		unset($gif);
2861
		$gif = link_interface_to_gif($interface);
2862
		if (!empty($gif))
2863
			array_walk($gif, 'interface_gif_configure');
2864

    
2865
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
2866
			unset($bridgetmp);
2867
			$bridgetmp = link_interface_to_bridge($interface);
2868
			if (!empty($bridgetmp))
2869
				interface_bridge_add_member($bridgetmp, $realif);
2870
		}
2871

    
2872
		$grouptmp = link_interface_to_group($interface);
2873
		if (!empty($grouptmp))
2874
			array_walk($grouptmp, 'interface_group_add_member');
2875

    
2876
		if ($interface == "lan")
2877
			/* make new hosts file */
2878
			system_hosts_generate();
2879

    
2880
		if ($reloadall == true) {
2881

    
2882
			/* reconfigure static routes (kernel may have deleted them) */
2883
			system_routing_configure($interface);
2884

    
2885
			/* reload ipsec tunnels */
2886
			vpn_ipsec_configure();
2887

    
2888
			/* restart dnsmasq */
2889
			services_dnsmasq_configure();
2890

    
2891
			/* update dyndns */
2892
			send_event("service reload dyndns {$interface}");
2893

    
2894
			/* reload captive portal */
2895
			captiveportal_init_rules();
2896
		}
2897
	}
2898

    
2899
	return 0;
2900
}
2901

    
2902
function interface_track6_configure($interface = "lan") {
2903
	global $config, $g;
2904
	$iflist = get_configured_interface_with_descr(false, true);
2905

    
2906
	$wancfg = $config['interfaces'][$interface];
2907
	$wanif = $wancfg['if'];
2908
	if (empty($wancfg))
2909
		$wancfg = array();
2910

    
2911
	$wanif = get_real_interface($interface);
2912
	
2913
	/* If the interface is not configured via another, exit */
2914
	if(!$wancfg['track6-interface'] <> "") {
2915
		return(false);
2916
	}
2917

    
2918
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
2919
	$realif = get_real_interface($interface);
2920
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
2921

    
2922
	$type = $config['interfaces'][$wancfg['track6-interface']]['ipaddrv6'];
2923
	switch($type) {
2924
		case "6to4":
2925
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2926
			interface_track6_6to4_configure($interface);
2927
			break;
2928
		case "6rd":
2929
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2930
			interface_track6_6rd_configure($interface);
2931
			break;
2932
		case "dhcp6":
2933
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2934
			interface_track6_dhcp6_configure($interface);
2935
			break;
2936
		default:
2937
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']} but unknown type {$type}");
2938
			break;
2939
	}
2940
	return 0;
2941
}
2942

    
2943

    
2944
function interface_track6_6rd_configure($interface = "lan") {
2945
	global $config, $g;
2946
	$iflist = get_configured_interface_with_descr(false, true);
2947

    
2948
	$lancfg = $config['interfaces'][$interface];
2949
	$lanif = $lancfg['if'];
2950
	if (empty($lancfg))
2951
		$lancfg = array();
2952

    
2953
	$lanif = get_real_interface($interface);
2954
	
2955
	/* If the interface is not configured via another, exit */
2956
	if(!$lancfg['track6-interface'] <> "") {
2957
		return(false);
2958
	}
2959
	if(!is_numeric($lancfg['track6-prefix-id']))
2960
		$lancfg['track6-prefix-id'] = 0;
2961
	
2962
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
2963
	$wanif = $wancfg['if'];
2964
	if (empty($wancfg))
2965
		$wancfg = array();
2966
	
2967
	$ip4address = find_interface_ip($wanif);
2968
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
2969
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
2970
		return false;
2971
	}
2972
	$hexwanv4 = return_hex_ipv4($ip4address);
2973
	
2974
	/* create the long prefix notation for math, save the prefix length */
2975
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
2976
	$rd6prefixlen = $rd6prefix[1];
2977
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
2978

    
2979
	/* binary presentation of the prefix for all 128 bits. */
2980
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
2981
	
2982
	/* just save the left prefix length bits */
2983
	$rd6lanbin = substr($rd6lanbin, 0, $rd6prefixlen);
2984
	/* add the v4 address, offset n bits from the left */
2985
	$rd6lanbin .= substr(sprintf("%032b", hexdec($hexwanv4)), (0 + $wancfg['prefix-6rd-v4plen']), 32);
2986

    
2987
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
2988
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
2989
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
2990
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
2991
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
2992
	/* fill the rest out with zeros */
2993
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
2994

    
2995
	/* convert the 128 bits for the lan address back into a valid IPv6 address */ 
2996
	$rd6lan = convert_128bit_to_ipv6($rd6lanbin) ."1";
2997
	
2998
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
2999
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3000
	return 0;
3001
}
3002

    
3003
function interface_track6_6to4_configure($interface = "lan") {
3004
	global $config, $g;
3005
	$iflist = get_configured_interface_with_descr(false, true);
3006

    
3007
	$lancfg = $config['interfaces'][$interface];
3008
	$lanif = $lancfg['if'];
3009
	if (empty($lancfg))
3010
		$lancfg = array();
3011

    
3012
	$lanif = get_real_interface($interface);
3013
	
3014
	/* If the interface is not configured via another, exit */
3015
	if(!$lancfg['track6-interface'] <> "") {
3016
		return(false);
3017
	}
3018
	if(!is_numeric($lancfg['track6-prefix-id']))
3019
		$lancfg['track6-prefix-id'] = 0;
3020
	
3021
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3022
	$wanif = $wancfg['if'];
3023
	if (empty($wancfg))
3024
		$wancfg = array();
3025
	
3026
	$ip4address = find_interface_ip($wanif);
3027
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3028
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3029
		return false;
3030
	}
3031
	$hexwanv4 = return_hex_ipv4($ip4address);
3032
	
3033
	/* create the long prefix notation for math, save the prefix length */
3034
	$sixto4prefix = "2002::";
3035
	$sixto4prefixlen = 16;
3036
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3037

    
3038
	/* binary presentation of the prefix for all 128 bits. */
3039
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3040
	
3041
	/* just save the left prefix length bits */
3042
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3043
	/* add the v4 address */
3044
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3045
	/* add the custom prefix id */
3046
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3047
	/* fill the rest out with zeros */
3048
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3049
	
3050
	/* convert the 128 bits for the lan address back into a valid IPv6 address */ 
3051
	$sixto4lan = convert_128bit_to_ipv6($sixto4lanbin) ."1";
3052
	
3053
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3054
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3055
	return 0;
3056
}
3057

    
3058
function interface_track6_dhcp6_configure($interface = "lan") {
3059
	global $config, $g;
3060
	$iflist = get_configured_interface_with_descr(false, true);
3061

    
3062
	$lancfg = $config['interfaces'][$interface];
3063
	$lanif = $lancfg['if'];
3064
	if (empty($lancfg))
3065
		$lancfg = array();
3066

    
3067
	$lanif = get_real_interface($interface);
3068
	
3069
	/* If the interface is not configured via another, exit */
3070
	if(!$lancfg['track6-interface'] <> "") {
3071
		return(false);
3072
	}
3073
	if(!is_numeric($lancfg['track6-prefix-id']))
3074
		$lancfg['track6-prefix-id'] = 0;
3075
	
3076
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3077
	$wanif = $wancfg['if'];
3078
	if (empty($wancfg))
3079
		$wancfg = array();
3080
	
3081
	$realwanif = get_real_interface($wanif);
3082
	if(is_readable("{$g['vardb_path']}/{$realwanif}_pd_ipv6")) {
3083
		$ifcfgipv6pfx = file_get_contents("{$g['vardb_path']}/{$realwanif}_pd_ipv6");
3084
	} else {
3085
		log_error("No DHCP-PD delegated prefix found, exiting");
3086
		return false;
3087
	}		
3088

    
3089
	log_error("Delegated IPv6 prefix is {$ifcfgipv6pfx}");
3090
	$ifcfgipv6pfxarr = explode("/", $ifcfgipv6pfx);
3091
	$ifcfgipv6 = $ifcfgipv6pfxarr[0];
3092
	
3093
	if(is_ipaddrv6($ifcfgipv6)) {
3094
		$dhcp6lanarr = explode(":", Net_IPv6::uncompress($ifcfgipv6));
3095
		/* we need to fold the $lancfg['track6-prefix-id'] into this address */
3096
		$dhcp6lanarr[4] = 0;
3097
		$dhcp6lanarr[5] = 0;
3098
		$dhcp6lanarr[6] = 0;
3099
		$dhcp6lanarr[7] = 1;
3100
		$dhcp6lan =  Net_IPv6::compress(implode(":", $dhcp6lanarr));
3101
		log_error("dhcp6 {$interface} with ipv6 address {$dhcp6lan} based on {$lancfg['track6-interface']}");
3102
		mwexec("/sbin/ifconfig {$lanif} inet6 {$dhcp6lan} prefixlen 64");
3103
	} else {
3104
		log_error("The DHCP-PD interface {$interface} address {$ifcfgipv6} is not a valid IPv6 address");
3105
	}
3106
	return 0;
3107
}
3108

    
3109
function interface_6rd_configure($interface = "wan") {
3110
	global $config, $g;
3111
	$iflist = get_configured_interface_with_descr(false, true);
3112

    
3113
	/* because this is a tunnel interface we can only function 
3114
	 *	with a public IPv4 address on the interface */
3115

    
3116
	$wancfg = $config['interfaces'][$interface];
3117
	$wanif = $wancfg['if'];
3118
	if (empty($wancfg))
3119
		$wancfg = array();
3120

    
3121
	$wanif = get_real_interface($interface);
3122
	
3123
	$ip4address = find_interface_ip($wanif);
3124
	$ip4gateway = get_interface_gateway($wanif);
3125
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3126
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3127
		return false;
3128
	}
3129
	$hexwanv4 = return_hex_ipv4($ip4address);
3130
	
3131
	if(!is_numeric($wancfg['prefix-6rd-v4plen']))
3132
		$wancfg['prefix-6rd-v4plen'] = 0;
3133

    
3134
	/* create the long prefix notation for math, save the prefix length */
3135
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3136
	$rd6prefixlen = $rd6prefix[1];
3137
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3138

    
3139
	/* we need the hex form of the broker IPv4 address */
3140
	$hexbrv4 = return_hex_ipv4($wancfg['gateway-6rd']);
3141
	
3142
	/* binary presentation of the prefix for all 128 bits. */
3143
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3144
		
3145
	/* just save the left prefix length bits */
3146
	$rd6brprefixbin = substr($rd6prefixbin, 0, $rd6prefixlen);
3147
	/* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
3148
	$rd6brprefixbin .= substr(sprintf("%032b", hexdec($hexbrv4)), $wancfg['prefix-6rd-v4plen'], 32);
3149
	/* fill out the rest with 0's */
3150
	$rd6brprefixbin = str_pad($rd6brprefixbin, 128, "0", STR_PAD_RIGHT);;
3151

    
3152
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3153
	$rd6brgw = convert_128bit_to_ipv6($rd6brprefixbin);
3154

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

    
3162
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3163
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3164

    
3165
	/* setup the stf interface */
3166
	/* use the srd device
3167
	mwexec("/sbin/ifconfig srd0 destroy");
3168
	mwexec("/sbin/ifconfig srd0 create");
3169
	mwexec("/sbin/ifconfig srd0 v4plen {$wancfg['prefix-6rd-v4plen']} pfix {$rd6prefix} plen {$rd6prefixlen} braddr {$wancfg['gateway-6rd']}");
3170
	log_error("Created 6rd interface srd0 v4plen {$wancfg['prefix-6rd-v4plen']} pfix {$rd6prefix} plen {$rd6prefixlen} braddr {$wancfg['gateway-6rd']}");
3171
	*/
3172
	/* stf approach only works when embedding the entire 32 bits of the v4 */
3173
	mwexec("/sbin/ifconfig stf0 destroy");
3174
	mwexec("/sbin/ifconfig stf0 create");
3175
	mwexec("/sbin/ifconfig stf0 inet6 {$rd6prefix}/{$rd6prefixlen}");
3176
	log_error("Created 6rd interface stf0 {$rd6prefix}/{$rd6prefixlen}");
3177

    
3178
	/* write out a default router file */
3179
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3180
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3181

    
3182
	if (is_ipaddrv4($ip4gateway)) {
3183
		mwexec("route change -host " . $wancfg['gateway-6rd'] . " {$ip4gateway}");
3184
	}
3185

    
3186
	/* configure dependent interfaces */
3187
	foreach($iflist as $if => $ifname) {
3188
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3189
			interface_track6_configure($if);
3190
	}
3191
	
3192
	return 0;
3193
}
3194

    
3195
function interface_6to4_configure($interface = "wan"){
3196
	global $config, $g;
3197
	$iflist = get_configured_interface_with_descr(false, true);
3198

    
3199
	/* because this is a tunnel interface we can only function 
3200
	 *	with a public IPv4 address on the interface */
3201

    
3202
	$wancfg = $config['interfaces'][$interface];
3203
	$wanif = $wancfg['if'];
3204
	if (empty($wancfg))
3205
		$wancfg = array();
3206

    
3207
	$wanif = get_real_interface($interface);
3208
	
3209
	$ip4address = find_interface_ip($wanif);
3210
	$ip4gateway = get_interface_gateway($wanif);
3211
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3212
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3213
		return false;
3214
	}
3215
	
3216
	/* create the long prefix notation for math, save the prefix length */
3217
	$stfprefixlen = 16;
3218
	$stfprefix = Net_IPv6::uncompress("2002::");
3219
	$stfarr = explode(":", $stfprefix);
3220
	$v4prefixlen = "0";
3221
	
3222
	/* we need the hex form of the interface IPv4 address */
3223
	$ip4arr = explode(".", $ip4address);
3224
	$hexwanv4 = "";
3225
	foreach($ip4arr as $octet)
3226
		$hexwanv4 .= sprintf("%02x", $octet);
3227

    
3228
	/* we need the hex form of the broker IPv4 address */
3229
	$ip4arr = explode(".", "192.88.99.1");
3230
	$hexbrv4 = "";
3231
	foreach($ip4arr as $octet)
3232
		$hexbrv4 .= sprintf("%02x", $octet);
3233
	
3234
	/* binary presentation of the prefix for all 128 bits. */
3235
	$stfprefixbin = "";
3236
	foreach($stfarr as $element) {
3237
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3238
	}
3239
	/* just save the left prefix length bits */
3240
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3241

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

    
3246
	/* for the local subnet too. */
3247
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3248
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3249

    
3250
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3251
	$stfbrarr = array();
3252
	$stfbrbinarr = array();
3253
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3254
	foreach($stfbrbinarr as $bin)
3255
		$stfbrarr[] = dechex(bindec($bin));
3256
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3257

    
3258
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3259
	$stflanarr = array();
3260
	$stflanbinarr = array();
3261
	$stflanbinarr = str_split($stflanbin, 16);
3262
	foreach($stflanbinarr as $bin)
3263
		$stflanarr[] = dechex(bindec($bin));
3264
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3265
	$stflanarr[7] = 1;
3266
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3267

    
3268
	/* setup the stf interface */
3269
	mwexec("/sbin/ifconfig stf0 destroy");
3270
	mwexec("/sbin/ifconfig stf0 create");
3271
	mwexec("/sbin/ifconfig stf0 inet6 {$stflanpr} prefixlen 16");
3272

    
3273
	log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for stf0, route {$stfbrgw}");
3274
	
3275
	/* write out a default router file */
3276
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3277
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3278

    
3279
	if (is_ipaddrv4($ip4gateway)) {
3280
		mwexec("route change -host 192.88.99.1 {$ip4gateway}");
3281
	}
3282

    
3283
	/* configure dependent interfaces */
3284
	foreach($iflist as $if => $ifname) {
3285
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3286
			interface_track6_configure($if);
3287
	}
3288
	
3289
	return 0;
3290
}
3291

    
3292
function interface_dhcpv6_configure($interface = "wan") {
3293
	global $config, $g;
3294
	$iflist = get_configured_interface_with_descr(false, true);
3295

    
3296
	$wancfg = $config['interfaces'][$interface];
3297
	$wanif = $wancfg['if'];
3298
	if (empty($wancfg))
3299
		$wancfg = array();
3300

    
3301
	$wanif = get_real_interface($interface);
3302

    
3303
	/* Add ISC IPv6 dhclient here */
3304
	$fd = fopen("{$g['varetc_path']}/dhcp6c_{$interface}.conf", "w");
3305
	if (!$fd) {
3306
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3307
		return 1;
3308
	}
3309

    
3310
	$dhcp6cconf = "interface \"{$wanif}\" {\n";
3311
	$dhcp6cconf .= "script \"/sbin/dhclient6-script\";\n";
3312
	$dhcp6cconf .= "}\n";
3313

    
3314
	fwrite($fd, $dhcp6cconf);
3315
	fclose($fd);
3316

    
3317
	/* accept router advertisements for this interface */
3318
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3319
	log_error("Accept router advertisements on interface {$wanif} ");
3320
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3321

    
3322
	/* run a filter configure so that the filter rules allow traffic before we launch the client */
3323
	filter_configure_sync();
3324
	sleep(3);
3325

    
3326
	/* dhclient -6
3327
	 * -T temprorary address
3328
	 * -S information only
3329
	 * -P Prefix
3330
	 * -N request address with temporary or prefix
3331
	*/
3332

    
3333
	$dhcp6c_options = "";
3334
	if($wancfg['ipaddrv6'] == "slaac") {
3335
		$dhcp6c_options .= "-S ";
3336
	}
3337
	if($wancfg['ipaddrv6'] == "dhcp6") {
3338
		$dhcp6c_options .= "-N ";
3339
	}
3340
	if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3341
		$dhcp6c_options .= "-P ";		
3342
	}
3343
	/* fire up dhcp6c for IPv6 first, this backgrounds immediately */
3344
	mwexec_bg("/usr/local/sbin/dhclient -6 {$dhcp6c_options} -cf {$g['varetc_path']}/dhcp6c_{$interface}.conf -lf {$g['varetc_path']}/dhcp6c_{$interface}.leases -pf {$g['varrun_path']}/dhcp6c_{$interface}.pid {$wanif}");
3345
	sleep(5);
3346
	return 0;
3347
}
3348

    
3349
function interface_dhcp_configure($interface = "wan") {
3350
	global $config, $g;
3351

    
3352
	$wancfg = $config['interfaces'][$interface];
3353
	$wanif = $wancfg['if'];
3354
	if (empty($wancfg))
3355
		$wancfg = array();
3356

    
3357
	/* generate dhclient_wan.conf */
3358
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3359
	if (!$fd) {
3360
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3361
		return 1;
3362
	}
3363

    
3364
	if ($wancfg['dhcphostname']) {
3365
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3366
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3367
	} else {
3368
		$dhclientconf_hostname = "";
3369
	}
3370

    
3371
	$wanif = get_real_interface($interface);
3372
	if (empty($wanif)) {
3373
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3374
		return 0;
3375
	}
3376
 	$dhclientconf = "";
3377
	
3378
	$dhclientconf .= <<<EOD
3379
interface "{$wanif}" {
3380
timeout 60;
3381
retry 15;
3382
select-timeout 0;
3383
initial-interval 1;
3384
	{$dhclientconf_hostname}
3385
	script "/sbin/dhclient-script";
3386
}
3387

    
3388
EOD;
3389

    
3390
if(is_ipaddr($wancfg['alias-address'])) {
3391
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3392
	$dhclientconf .= <<<EOD
3393
alias {
3394
	interface  "{$wanif}";
3395
	fixed-address {$wancfg['alias-address']};
3396
	option subnet-mask {$subnetmask};
3397
}
3398

    
3399
EOD;
3400
}
3401
	fwrite($fd, $dhclientconf);
3402
	fclose($fd);
3403

    
3404
	/* bring wan interface up before starting dhclient */
3405
	if($wanif)
3406
		interfaces_bring_up($wanif);
3407
	else 
3408
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3409

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

    
3413
	return 0;
3414
}
3415

    
3416
function interfaces_group_setup() {
3417
	global $config;
3418

    
3419
	if (!is_array($config['ifgroups']['ifgroupentry']))
3420
		return;
3421

    
3422
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3423
		interface_group_setup($groupar);
3424

    
3425
	return;
3426
}
3427

    
3428
function interface_group_setup(&$groupname /* The parameter is an array */) {
3429
	global $config;
3430

    
3431
	if (!is_array($groupname))
3432
		return;
3433
	$members = explode(" ", $groupname['members']);
3434
	foreach($members as $ifs) {
3435
		$realif = get_real_interface($ifs);
3436
		if ($realif)
3437
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3438
	}
3439

    
3440
	return;
3441
}
3442

    
3443
function interface_group_add_member($interface, $groupname) {
3444
	$interface = get_real_interface($interface);
3445
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
3446
}
3447
 
3448
/* COMPAT Function */
3449
function convert_friendly_interface_to_real_interface_name($interface) {
3450
	return get_real_interface($interface);
3451
}
3452

    
3453
/* COMPAT Function */
3454
function get_real_wan_interface($interface = "wan") {
3455
	return get_real_interface($interface);
3456
}
3457

    
3458
/* COMPAT Function */
3459
function get_current_wan_address($interface = "wan") {
3460
	return get_interface_ip($interface);
3461
}
3462

    
3463
/*
3464
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3465
 */
3466
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3467
        global $config;
3468

    
3469
	if (stristr($interface, "_vip")) {
3470
                foreach ($config['virtualip']['vip'] as $counter => $vip) {
3471
                        if ($vip['mode'] == "carp")  {
3472
                                if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3473
                                        return $vip['interface'];
3474
                        }
3475
                }
3476
        }
3477

    
3478
        /* XXX: For speed reasons reference directly the interface array */
3479
	$ifdescrs = &$config['interfaces'];
3480
        //$ifdescrs = get_configured_interface_list(false, true);
3481

    
3482
        foreach ($ifdescrs as $if => $ifname) {
3483
                if ($config['interfaces'][$if]['if'] == $interface)
3484
                        return $if;
3485

    
3486
                if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
3487
                        return $if;
3488

    
3489
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
3490
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
3491
		/*
3492
                $int = get_parent_interface($if);
3493
                if ($int[0] == $interface)
3494
                        return $ifname;
3495
		*/
3496
        }
3497
        return NULL;
3498
}
3499

    
3500
/* attempt to resolve interface to friendly descr */
3501
function convert_friendly_interface_to_friendly_descr($interface) {
3502
        global $config;
3503

    
3504
        switch ($interface) {
3505
        case "l2tp":
3506
        	$ifdesc = "L2TP";
3507
                break;
3508
	case "pptp":
3509
		$ifdesc = "PPTP";
3510
		break;
3511
	case "pppoe":
3512
		$ifdesc = "PPPoE";
3513
		break;
3514
	case "openvpn":
3515
		$ifdesc = "OpenVPN";
3516
		break;
3517
	case "enc0":
3518
	case "ipsec":
3519
		$ifdesc = "IPsec";
3520
		break;
3521
        default:
3522
                if (isset($config['interfaces'][$interface])) {
3523
                        if (empty($config['interfaces'][$interface]['descr']))
3524
                                $ifdesc = strtoupper($interface);
3525
                        else
3526
                                $ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3527
			break;
3528
		} else if (stristr($interface, "_vip")) {
3529
			if (is_array($config['virtualip']['vip'])) {
3530
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3531
					if ($vip['mode'] == "carp")  {
3532
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3533
							return "{$vip['subnet']} - {$vip['descr']}";
3534
					}
3535
				}
3536
                        }
3537
                } else {
3538
			/* if list */
3539
			$ifdescrs = get_configured_interface_with_descr(false, true);
3540
			foreach ($ifdescrs as $if => $ifname) {
3541
				if ($if == $interface || $ifname == $interface)
3542
					return $ifname;
3543
			}
3544
		}
3545
                break;
3546
        }
3547

    
3548
        return $ifdesc;
3549
}
3550

    
3551
function convert_real_interface_to_friendly_descr($interface) {
3552
        global $config;
3553

    
3554
        $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3555

    
3556
        if ($ifdesc) {
3557
                $iflist = get_configured_interface_with_descr(false, true);
3558
                return $iflist[$ifdesc];
3559
        }
3560

    
3561
        return $interface;
3562
}
3563

    
3564
/*
3565
 *  get_parent_interface($interface):
3566
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3567
 *				or virtual interface (i.e. vlan)
3568
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3569
 *			-- returns $interface passed in if $interface parent is not found
3570
 *			-- returns empty array if an invalid interface is passed
3571
 *	(Only handles ppps and vlans now.)
3572
 */
3573
function get_parent_interface($interface) {
3574
	global $config;
3575

    
3576
	$parents = array();
3577
	//Check that we got a valid interface passed
3578
	$realif = get_real_interface($interface);
3579
	if ($realif == NULL)
3580
		return $parents;
3581

    
3582
	// If we got a real interface, find it's friendly assigned name
3583
	$interface = convert_real_interface_to_friendly_interface_name($interface);
3584
		
3585
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3586
		$ifcfg = $config['interfaces'][$interface];
3587
		switch ($ifcfg['ipaddr']) {
3588
			case "ppp":
3589
			case "pppoe":
3590
			case "pptp":
3591
			case "l2tp":
3592
				if (empty($parents))
3593
					if (is_array($config['ppps']['ppp']))
3594
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3595
							if ($ppp_if == $ppp['if']) {
3596
								$ports = explode(',', $ppp['ports']);
3597
								foreach ($ports as $pid => $parent_if) 
3598
									$parents[$pid] = get_real_interface($parent_if);
3599
								break;
3600
							}
3601
						}
3602
				break;
3603
			case "dhcp":
3604
			case "static":
3605
			default:
3606
				// Handle _vlans
3607
				if (strstr($realif,"_vlan"))
3608
					if (is_array($config['vlans']['vlan'])) 
3609
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3610
							if ($ifcfg['if'] == $vlan['vlanif']){
3611
								$parents[0] = $vlan['if'];
3612
								break;
3613
							}
3614
				break;
3615
		}
3616
	}
3617
	
3618
	if (empty($parents))
3619
		$parents[0] = $realif;
3620
	
3621
	return $parents;
3622
}
3623

    
3624
function interface_is_wireless_clone($wlif) {
3625
	if(!stristr($wlif, "_wlan")) {
3626
		return false;
3627
	} else {
3628
		return true;
3629
	}
3630
}
3631

    
3632
function interface_get_wireless_base($wlif) {
3633
	if(!stristr($wlif, "_wlan")) {
3634
		return $wlif;
3635
	} else {
3636
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3637
	}
3638
}
3639

    
3640
function interface_get_wireless_clone($wlif) {
3641
	if(!stristr($wlif, "_wlan")) {
3642
		return $wlif . "_wlan0";
3643
	} else {
3644
		return $wlif;
3645
	}
3646
}
3647

    
3648
function get_real_interface($interface = "wan") {
3649
    global $config;
3650

    
3651
	$wanif = NULL;
3652

    
3653
	switch ($interface) {
3654
	case "l2tp":
3655
		$wanif = "l2tp";
3656
		break;
3657
	case "pptp":
3658
		$wanif = "pptp";
3659
		break;
3660
	case "pppoe":
3661
		$wanif = "pppoe";
3662
		break;
3663
	case "openvpn":
3664
		$wanif = "openvpn";
3665
		break;
3666
	case "ipsec":
3667
	case "enc0":
3668
		$wanif = "enc0";
3669
		break;
3670
	case "ppp":
3671
		$wanif = "ppp";
3672
		break;
3673
	default:
3674
		// If a real interface was alread passed simply
3675
		// pass the real interface back.  This encourages
3676
		// the usage of this function in more cases so that
3677
		// we can combine logic for more flexibility.
3678
		if(does_interface_exist($interface)) {
3679
			$wanif = $interface;
3680
			break;
3681
		}
3682

    
3683
		if (empty($config['interfaces'][$interface]))
3684
			break;
3685

    
3686
		$cfg = &$config['interfaces'][$interface];
3687

    
3688
		// Wireless cloned NIC support (FreeBSD 8+)
3689
		// interface name format: $parentnic_wlanparentnic#
3690
		// example: ath0_wlan0
3691
		if (is_interface_wireless($cfg['if'])) {
3692
			$wanif = interface_get_wireless_clone($cfg['if']);
3693
			break;
3694
		}
3695
		/*
3696
		if (empty($cfg['if'])) {
3697
			$wancfg = $cfg['if'];
3698
			break;
3699
		}
3700
		*/
3701

    
3702
		switch ($cfg['ipaddr']) {
3703
			case "pppoe": 
3704
			case "pptp": 
3705
			case "l2tp": 
3706
			case "ppp":
3707
				$wanif = $cfg['if'];
3708
				break;
3709
			default:
3710
				$wanif = $cfg['if'];
3711
				break;
3712
		}
3713
		break;
3714
	}
3715

    
3716
    return $wanif;
3717
}
3718

    
3719
/* Guess the physical interface by providing a IP address */
3720
function guess_interface_from_ip($ipaddress) {
3721
	if(! is_ipaddr($ipaddress)) {
3722
		return false;
3723
	}
3724
	if(is_ipaddrv4($ipaddress)) {
3725
		/* create a route table we can search */
3726
		exec("netstat -rnWf inet", $output, $ret);
3727
		foreach($output as $line) {
3728
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
3729
				$fields = preg_split("/[ ]+/", $line);
3730
				if(ip_in_subnet($ipaddress, $fields[0])) {
3731
					return $fields[6];
3732
				}
3733
			}
3734
		}
3735
	}
3736
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
3737
	if(is_ipaddrv6($ipaddress)) {
3738
		/* create a route table we can search */
3739
		exec("netstat -rnWf inet6", $output, $ret);
3740
		foreach($output as $line) {
3741
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
3742
				$fields = preg_split("/[ ]+/", $line);
3743
				if(ip_in_subnet($ipaddress, $fields[0])) {
3744
					return $fields[6];
3745
				}
3746
			}
3747
		}
3748
	}
3749
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
3750
	if(empty($ret)) {
3751
        	return false;
3752
	}
3753
	return $ret;
3754
}
3755

    
3756
/*
3757
 * find_ip_interface($ip): return the interface where an ip is defined
3758
 *   (or if $bits is specified, where an IP within the subnet is defined)
3759
 */
3760
function find_ip_interface($ip, $bits = null)
3761
{
3762
	/* if list */
3763
	$ifdescrs = get_configured_interface_list();
3764
		
3765
	foreach ($ifdescrs as $ifdescr => $ifname) {
3766
		if ($bits === null) {
3767
			if ($ip == get_interface_ip($ifname)) {
3768
				$int = get_real_interface($ifname);
3769
				return $int;
3770
			}
3771
		}
3772
		else {
3773
			if (ip_in_subnet(get_interface_ip($ifname), $ip . "/" . $bits)) {
3774
				$int = get_real_interface($ifname);
3775
				return $int;
3776
			}
3777
		}
3778
	}
3779
	return false;
3780
}
3781

    
3782
/*
3783
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
3784
 *   (or if $bits is specified, where an IP within the subnet is found)
3785
 */
3786
function find_virtual_ip_alias($ip, $bits = null) {
3787
	global $config;
3788
	if (!is_array($config['virtualip']['vip'])) {
3789
		return false;
3790
	}
3791
	foreach ($config['virtualip']['vip'] as $vip) {
3792
		if ($vip['mode'] === "ipalias") {
3793
			if ($bits === null) {
3794
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
3795
					return $vip;
3796
				}
3797
			}
3798
			else {
3799
				if (check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) {
3800
					return $vip;
3801
				}
3802
			}
3803
		}
3804
	}
3805
	return false;
3806
}
3807

    
3808
/*
3809
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
3810
 */
3811
function find_number_of_created_carp_interfaces() {
3812
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
3813
}
3814

    
3815
function get_all_carp_interfaces() {
3816
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
3817
	$ints = explode(" ", $ints);
3818
	return $ints;
3819
}
3820

    
3821
/*
3822
 * find_carp_interface($ip): return the carp interface where an ip is defined
3823
 */
3824
function find_carp_interface($ip) {
3825
	global $config;
3826
	if (is_array($config['virtualip']['vip'])) {
3827
		foreach ($config['virtualip']['vip'] as $vip) {
3828
			if ($vip['mode'] == "carp") {
3829
				if(is_ipaddrv4($ip)) {
3830
					$carp_ip = get_interface_ip($vip['interface']);
3831
				}
3832
				if(is_ipaddrv6($ip)) {
3833
					$carp_ip = get_interface_ipv6($vip['interface']);
3834
				}
3835
				exec("/sbin/ifconfig", $output, $return);
3836
				foreach($output as $line) {
3837
					$elements = preg_split("/[ ]+/i", $line);
3838
					if(strstr($elements[0], "vip"))
3839
						$curif = str_replace(":", "", $elements[0]);
3840
					if(stristr($line, $ip)) {
3841
						$if = $curif;
3842
						continue;
3843
					}
3844
				}
3845

    
3846
				if ($if)
3847
					return $if;
3848
			}
3849
		}
3850
	}
3851
}
3852

    
3853
function link_carp_interface_to_parent($interface) {
3854
        global $config;
3855

    
3856
        if ($interface == "")
3857
                return;
3858

    
3859
        $carp_ip = get_interface_ip($interface);
3860
        if (!is_ipaddr($carp_ip))
3861
                return;
3862

    
3863
        /* if list */
3864
        $ifdescrs = get_configured_interface_list();
3865
        foreach ($ifdescrs as $ifdescr => $ifname) {
3866
                $interfaceip = get_interface_ip($ifname);
3867
                $subnet_bits = get_interface_subnet($ifname);
3868
                $subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3869
                if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3870
                        return $ifname;
3871
        }
3872

    
3873
        return "";
3874
}
3875

    
3876
/****f* interfaces/link_ip_to_carp_interface
3877
 * NAME
3878
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3879
 * INPUTS
3880
 *   $ip
3881
 * RESULT
3882
 *   $carp_ints
3883
 ******/
3884
function link_ip_to_carp_interface($ip) {
3885
        global $config;
3886

    
3887
        if (!is_ipaddr($ip))
3888
                return;
3889

    
3890
        $carp_ints = "";
3891
        if (is_array($config['virtualip']['vip'])) {
3892
		$first = 0;
3893
		$carp_int = array();
3894
                foreach ($config['virtualip']['vip'] as $vip) {
3895
                        if ($vip['mode'] == "carp") {
3896
                                $carp_ip = $vip['subnet'];
3897
                                $carp_sn = $vip['subnet_bits'];
3898
                                $carp_nw = gen_subnet($carp_ip, $carp_sn);
3899
                                if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
3900
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
3901
				}
3902
                        }
3903
                }
3904
		if (!empty($carp_int))
3905
			$carp_ints = implode(" ", array_unique($carp_int));
3906
        }
3907

    
3908
        return $carp_ints;
3909
}
3910

    
3911
function link_interface_to_vlans($int, $action = "") {
3912
	global $config;
3913

    
3914
	if (empty($int))
3915
		return;
3916

    
3917
	if (is_array($config['vlans']['vlan'])) {
3918
                foreach ($config['vlans']['vlan'] as $vlan) {
3919
			if ($int == $vlan['if']) {
3920
				if ($action == "update") {
3921
					interfaces_bring_up($int);
3922
				} else if ($action == "")
3923
					return $vlan;
3924
			}
3925
		}
3926
	}
3927
}
3928

    
3929
function link_interface_to_vips($int, $action = "") {
3930
        global $config;
3931

    
3932
        if (is_array($config['virtualip']['vip'])) {
3933
		foreach ($config['virtualip']['vip'] as $vip) {
3934
			if ($int == $vip['interface']) {
3935
				if ($action == "update")
3936
					interfaces_vips_configure($int);
3937
				else
3938
					return $vip;
3939
			}
3940
		}
3941
	}
3942
}
3943

    
3944
/****f* interfaces/link_interface_to_bridge
3945
 * NAME
3946
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3947
 * INPUTS
3948
 *   $ip
3949
 * RESULT
3950
 *   bridge[0-99]
3951
 ******/
3952
function link_interface_to_bridge($int) {
3953
        global $config;
3954

    
3955
        if (is_array($config['bridges']['bridged'])) {
3956
                foreach ($config['bridges']['bridged'] as $bridge) {
3957
			if (in_array($int, explode(',', $bridge['members'])))
3958
                                return "{$bridge['bridgeif']}";
3959
		}
3960
	}
3961
}
3962

    
3963
function link_interface_to_group($int) {
3964
        global $config;
3965

    
3966
	$result = array();
3967

    
3968
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3969
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3970
			if (in_array($int, explode(" ", $group['members'])))
3971
				$result[$group['ifname']] = $int;
3972
		}
3973
	}
3974

    
3975
	return $result;
3976
}
3977

    
3978
function link_interface_to_gre($interface) {
3979
        global $config;
3980

    
3981
	$result = array();
3982

    
3983
        if (is_array($config['gres']['gre'])) {
3984
                foreach ($config['gres']['gre'] as $gre)
3985
                        if($gre['if'] == $interface)
3986
				$result[] = $gre;
3987
	}
3988

    
3989
	return $result;
3990
}
3991

    
3992
function link_interface_to_gif($interface) {
3993
        global $config;
3994

    
3995
	$result = array();
3996

    
3997
        if (is_array($config['gifs']['gif'])) {
3998
                foreach ($config['gifs']['gif'] as $gif)
3999
                        if($gif['if'] == $interface)
4000
                                $result[] = $gif;
4001
	}
4002

    
4003
	return $result;
4004
}
4005

    
4006
/*
4007
 * find_interface_ip($interface): return the interface ip (first found)
4008
 */
4009
function find_interface_ip($interface, $flush = false)
4010
{
4011
	global $interface_ip_arr_cache;
4012
	global $interface_sn_arr_cache;
4013

    
4014
	$interface = str_replace("\n", "", $interface);
4015
	
4016
	if (!does_interface_exist($interface))
4017
		return;
4018

    
4019
	/* Setup IP cache */
4020
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4021
		$ifinfo = pfSense_get_interface_addresses($interface);
4022
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4023
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4024
	}
4025

    
4026
	return $interface_ip_arr_cache[$interface];
4027
}
4028

    
4029
/*
4030
 * find_interface_ipv6($interface): return the interface ip (first found)
4031
 */
4032
function find_interface_ipv6($interface, $flush = false)
4033
{
4034
	global $interface_ipv6_arr_cache;
4035
	global $interface_snv6_arr_cache;
4036
	global $config;
4037
	
4038
	$interface = trim($interface);
4039
	$interface = get_real_interface($interface);
4040
	
4041
	if (!does_interface_exist($interface))
4042
		return;
4043

    
4044
	/* Setup IP cache */
4045
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4046
		$ifinfo = pfSense_get_interface_addresses($interface);
4047
		// FIXME: Add IPv6 support to the pfSense module
4048
		exec("/sbin/ifconfig {$interface} inet6", $output);
4049
		foreach($output as $line) {
4050
			if(preg_match("/inet6/", $line)) {
4051
				$parts = explode(" ", $line);
4052
				if(! preg_match("/fe80::/", $parts[1])) {
4053
					$ifinfo['ipaddrv6'] = $parts[1];
4054
					if($parts[2] == "-->") {
4055
						$parts[5] = "126";
4056
						$ifinfo['subnetbitsv6'] = $parts[5];
4057
					} else {
4058
						$ifinfo['subnetbitsv6'] = $parts[3];
4059
					}
4060
				}
4061
			}
4062
		}
4063
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4064
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4065
	}
4066

    
4067
	return $interface_ipv6_arr_cache[$interface];
4068
}
4069

    
4070
/*
4071
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4072
 */
4073
function find_interface_ipv6_ll($interface, $flush = false)
4074
{
4075
	global $interface_llv6_arr_cache;
4076
	global $config;
4077
	
4078
	$interface = str_replace("\n", "", $interface);
4079
	
4080
	if (!does_interface_exist($interface))
4081
		return;
4082

    
4083
	/* Setup IP cache */
4084
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4085
		$ifinfo = pfSense_get_interface_addresses($interface);
4086
		// FIXME: Add IPv6 support to the pfSense module
4087
		exec("/sbin/ifconfig {$interface} inet6", $output);
4088
		foreach($output as $line) {
4089
			if(preg_match("/inet6/", $line)) {
4090
				$parts = explode(" ", $line);
4091
				if(preg_match("/fe80::/", $parts[1])) {
4092
					$partsaddress = explode("%", $parts[1]);
4093
					$ifinfo['linklocal'] = $partsaddress[0];
4094
				}
4095
			}
4096
		}
4097
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4098
	}
4099
	return $interface_llv6_arr_cache[$interface];
4100
}
4101

    
4102
function find_interface_subnet($interface, $flush = false)
4103
{
4104
	global $interface_sn_arr_cache;
4105
	global $interface_ip_arr_cache;
4106

    
4107
	$interface = str_replace("\n", "", $interface);
4108
	if (does_interface_exist($interface) == false)
4109
		return;
4110

    
4111
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4112
		$ifinfo = pfSense_get_interface_addresses($interface);
4113
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4114
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4115
        }
4116

    
4117
	return $interface_sn_arr_cache[$interface];
4118
}
4119

    
4120
function find_interface_subnetv6($interface, $flush = false)
4121
{
4122
	global $interface_snv6_arr_cache;
4123
	global $interface_ipv6_arr_cache;
4124

    
4125
	$interface = str_replace("\n", "", $interface);
4126
	if (does_interface_exist($interface) == false)
4127
		return;
4128

    
4129
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4130
		$ifinfo = pfSense_get_interface_addresses($interface);
4131
		// FIXME: Add IPv6 support to the pfSense module
4132
		exec("/sbin/ifconfig {$interface} inet6", $output);
4133
		foreach($output as $line) {
4134
			if(preg_match("/inet6/", $line)) {
4135
				$parts = explode(" ", $line);
4136
				if(! preg_match("/fe80::/", $parts[1])) {
4137
					$ifinfo['ipaddrv6'] = $parts[1];
4138
					if($parts[2] == "-->") {
4139
						$parts[5] = "126";
4140
						$ifinfo['subnetbitsv6'] = $parts[5];
4141
					} else {
4142
						$ifinfo['subnetbitsv6'] = $parts[3];
4143
					}
4144
				}
4145
			}
4146
		}
4147
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4148
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4149
        }
4150

    
4151
	return $interface_snv6_arr_cache[$interface];
4152
}
4153

    
4154
function ip_in_interface_alias_subnet($interface, $ipalias) {
4155
	global $config;
4156

    
4157
	if (empty($interface) || !is_ipaddr($ipalias))
4158
		return false;
4159
	if (is_array($config['virtualip']['vip'])) {
4160
                foreach ($config['virtualip']['vip'] as $vip) {
4161
                        switch ($vip['mode']) {
4162
                        case "ipalias":
4163
                                if ($vip['interface'] <> $interface)
4164
                                        break;
4165
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
4166
					return true;
4167
                                break;
4168
                        }
4169
                }
4170
	}
4171

    
4172
	return false;
4173
}
4174

    
4175
function get_interface_ip($interface = "wan")
4176
{
4177
	$realif = get_failover_interface($interface);
4178
	if (!$realif) {
4179
		if (preg_match("/^carp/i", $interface))
4180
			$realif = $interface;
4181
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4182
			$realif = $interface;
4183
		else
4184
			return null;
4185
	}
4186

    
4187
	$curip = find_interface_ip($realif);
4188
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4189
		return $curip;
4190
	else
4191
		return null;
4192
}
4193

    
4194
function get_interface_ipv6($interface = "wan")
4195
{
4196
	global $config;
4197
	$realif = get_failover_interface($interface);
4198
	switch($config['interfaces'][$interface]['ipaddrv6']) {
4199
		case "6rd":
4200
		case "6to4":
4201
			$realif = "stf0";
4202
			break;
4203
	}
4204
	if (!$realif) {
4205
		if (preg_match("/^carp/i", $interface))
4206
			$realif = $interface;
4207
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4208
			$realif = $interface;
4209
		else
4210
			return null;
4211
	}
4212

    
4213
	$curip = find_interface_ipv6($realif);
4214
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4215
		return $curip;
4216
	else
4217
		return null;
4218
}
4219

    
4220
function get_interface_linklocal($interface = "wan")
4221
{
4222
	$realif = get_failover_interface($interface);
4223
	if (!$realif) {
4224
		if (preg_match("/^carp/i", $interface))
4225
			$realif = $interface;
4226
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4227
			$realif = $interface;
4228
		else
4229
			return null;
4230
	}
4231

    
4232
	$curip = find_interface_ipv6_ll($realif);
4233
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4234
		return $curip;
4235
	else
4236
		return null;
4237
}
4238

    
4239
function get_interface_subnet($interface = "wan")
4240
{
4241
	$realif = get_real_interface($interface);
4242
	if (!$realif) {
4243
                if (preg_match("/^carp/i", $interface))
4244
                        $realif = $interface;
4245
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4246
                        $realif = $interface;
4247
                else
4248
                        return null;
4249
        }
4250

    
4251
	$cursn = find_interface_subnet($realif);
4252
	if (!empty($cursn))
4253
		return $cursn;
4254

    
4255
	return null;
4256
}
4257

    
4258
function get_interface_subnetv6($interface = "wan")
4259
{
4260
	$realif = get_real_interface($interface);
4261
	if (!$realif) {
4262
                if (preg_match("/^carp/i", $interface))
4263
                        $realif = $interface;
4264
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4265
                        $realif = $interface;
4266
                else
4267
                        return null;
4268
        }
4269

    
4270
	$cursn = find_interface_subnetv6($realif);
4271
	if (!empty($cursn))
4272
		return $cursn;
4273

    
4274
	return null;
4275
}
4276

    
4277
/* return outside interfaces with a gateway */
4278
function get_interfaces_with_gateway() {
4279
	global $config;
4280

    
4281
	$ints = array();
4282

    
4283
	/* loop interfaces, check config for outbound */
4284
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4285
		switch ($ifname['ipaddr']) {
4286
			case "dhcp":
4287
			case "ppp";
4288
			case "pppoe":
4289
			case "pptp":
4290
			case "l2tp":
4291
			case "ppp";
4292
				$ints[$ifdescr] = $ifdescr;
4293
			break;
4294
			default:
4295
				if (substr($ifname['if'], 0, 5) ==  "ovpnc" ||
4296
				    !empty($ifname['gateway']))
4297
					$ints[$ifdescr] = $ifdescr;
4298
			break;
4299
		}
4300
	}
4301
	return $ints;
4302
}
4303

    
4304
/* return true if interface has a gateway */
4305
function interface_has_gateway($friendly) {
4306
	global $config;
4307

    
4308
	if (!empty($config['interfaces'][$friendly])) {
4309
		$ifname = &$config['interfaces'][$friendly];
4310
		switch ($ifname['ipaddr']) {
4311
			case "dhcp":
4312
			case "pppoe":
4313
			case "pptp":
4314
			case "l2tp":
4315
			case "ppp";
4316
				return true;
4317
			break;
4318
			default:
4319
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
4320
					return true;
4321
				if (!empty($ifname['gateway']))
4322
					return true;
4323
			break;
4324
		}
4325
	}
4326

    
4327
	return false;
4328
}
4329

    
4330
/* return true if interface has a gateway */
4331
function interface_has_gatewayv6($friendly) {
4332
	global $config;
4333

    
4334
	if (!empty($config['interfaces'][$friendly])) {
4335
		$ifname = &$config['interfaces'][$friendly];
4336
		switch ($ifname['ipaddrv6']) {
4337
			case "slaac":
4338
			case "dhcp6":
4339
				return true;
4340
				break;
4341
			case "6to4":
4342
				return true;
4343
				break;
4344
			case "6rd":
4345
				return true;
4346
				break;
4347
			default:
4348
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
4349
					return true;
4350
				if (!empty($ifname['gatewayv6']))
4351
					return true;
4352
				break;
4353
		}
4354
	}
4355

    
4356
	return false;
4357
}
4358

    
4359
/****f* interfaces/is_altq_capable
4360
 * NAME
4361
 *   is_altq_capable - Test if interface is capable of using ALTQ
4362
 * INPUTS
4363
 *   $int            - string containing interface name
4364
 * RESULT
4365
 *   boolean         - true or false
4366
 ******/
4367

    
4368
function is_altq_capable($int) {
4369
        /* Per:
4370
         * http://www.freebsd.org/cgi/man.cgi?query=altq&manpath=FreeBSD+7.2-current&format=html
4371
         * Only the following drivers have ALTQ support
4372
         */
4373
	$capable = array("age", "alc", "ale", "an", "ath", "aue", "awi", "bce",
4374
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "fxp", "gem",
4375
			"hme", "igb", "ipw", "iwi", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
4376
			"npe", "nve", "ral", "re", "rl", "rum", "run", "bwn", "sf", "sis", "sk",
4377
			"ste", "stge", "txp", "udav", "ural", "vge", "vr", "wi", "xl",
4378
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
4379
			"l2tp", "ppp", "vtnet");
4380

    
4381
        $int_family = preg_split("/[0-9]+/", $int);
4382

    
4383
        if (in_array($int_family[0], $capable))
4384
                return true;
4385
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4386
		return true;
4387
	else if (stristr($int, "vlan")) /* VLANs are name $parent_$vlan now */
4388
		return true;
4389
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4390
		return true;
4391
        else
4392
                return false;
4393
}
4394

    
4395
/****f* interfaces/is_interface_wireless
4396
 * NAME
4397
 *   is_interface_wireless - Returns if an interface is wireless
4398
 * RESULT
4399
 *   $tmp       - Returns if an interface is wireless
4400
 ******/
4401
function is_interface_wireless($interface) {
4402
        global $config, $g;
4403

    
4404
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
4405
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
4406
                if (preg_match($g['wireless_regex'], $interface)) {
4407
                        if (isset($config['interfaces'][$friendly]))
4408
                                $config['interfaces'][$friendly]['wireless'] = array();
4409
                        return true;
4410
                }
4411
                return false;
4412
        } else
4413
                return true;
4414
}
4415

    
4416
function get_wireless_modes($interface) {
4417
	/* return wireless modes and channels */
4418
	$wireless_modes = array();
4419

    
4420
	$cloned_interface = get_real_interface($interface);
4421

    
4422
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4423
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4424
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4425
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4426

    
4427
		$interface_channels = "";
4428
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4429
		$interface_channel_count = count($interface_channels);
4430

    
4431
		$c = 0;
4432
		while ($c < $interface_channel_count)
4433
		{
4434
			$channel_line = explode(",", $interface_channels["$c"]);
4435
			$wireless_mode = trim($channel_line[0]);
4436
			$wireless_channel = trim($channel_line[1]);
4437
			if(trim($wireless_mode) != "") {
4438
				/* if we only have 11g also set 11b channels */
4439
				if($wireless_mode == "11g") {
4440
					if(!isset($wireless_modes["11b"]))
4441
						$wireless_modes["11b"] = array();
4442
				} else if($wireless_mode == "11g ht") {
4443
					if(!isset($wireless_modes["11b"]))
4444
						$wireless_modes["11b"] = array();
4445
					if(!isset($wireless_modes["11g"]))
4446
						$wireless_modes["11g"] = array();
4447
					$wireless_mode = "11ng";
4448
				} else if($wireless_mode == "11a ht") {
4449
					if(!isset($wireless_modes["11a"]))
4450
						$wireless_modes["11a"] = array();
4451
					$wireless_mode = "11na";
4452
				}
4453
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4454
			}
4455
			$c++;
4456
		}
4457
	}
4458
	return($wireless_modes);
4459
}
4460

    
4461
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4462
function get_wireless_channel_info($interface) {
4463
	$wireless_channels = array();
4464

    
4465
	$cloned_interface = get_real_interface($interface);
4466

    
4467
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4468
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4469
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4470
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4471

    
4472
		$interface_channels = "";
4473
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4474

    
4475
		foreach ($interface_channels as $channel_line) {
4476
			$channel_line = explode(",", $channel_line);
4477
			if(!isset($wireless_channels[$channel_line[0]]))
4478
				$wireless_channels[$channel_line[0]] = $channel_line;
4479
		}
4480
	}
4481
	return($wireless_channels);
4482
}
4483

    
4484
/****f* interfaces/get_interface_mtu
4485
 * NAME
4486
 *   get_interface_mtu - Return the mtu of an interface
4487
 * RESULT
4488
 *   $tmp       - Returns the mtu of an interface
4489
 ******/
4490
function get_interface_mtu($interface) {
4491
        $mtu = pfSense_get_interface_addresses($interface);
4492
        return $mtu['mtu'];
4493
}
4494

    
4495
function get_interface_mac($interface) {
4496

    
4497
	$macinfo = pfSense_get_interface_addresses($interface);
4498
	return $macinfo["macaddr"];
4499
}
4500

    
4501
/****f* pfsense-utils/generate_random_mac_address
4502
 * NAME
4503
 *   generate_random_mac - generates a random mac address
4504
 * INPUTS
4505
 *   none
4506
 * RESULT
4507
 *   $mac - a random mac address
4508
 ******/
4509
function generate_random_mac_address() {
4510
        $mac = "02";
4511
        for($x=0; $x<5; $x++)
4512
                $mac .= ":" . dechex(rand(16, 255));
4513
        return $mac;
4514
}
4515

    
4516
/****f* interfaces/is_jumbo_capable
4517
 * NAME
4518
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4519
 * INPUTS
4520
 *   $int             - string containing interface name
4521
 * RESULT
4522
 *   boolean          - true or false
4523
 ******/
4524
function is_jumbo_capable($iface) {
4525

    
4526

    
4527
	$iface = trim($iface);
4528
	$capable = pfSense_get_interface_addresses($iface);
4529
	if (isset($capable['caps']['vlanmtu']))
4530
                return true;
4531

    
4532

    
4533

    
4534

    
4535

    
4536
	return false;
4537
}
4538

    
4539
function setup_pppoe_reset_file($pppif, $iface="") {
4540
	global $g;
4541
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4542

    
4543
	if(!empty($iface) && !empty($pppif)){
4544
		$cron_cmd = <<<EOD
4545
#!/bin/sh
4546
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4547
/usr/bin/logger -t pppoe{$iface} "PPPoE periodic reset executed on {$iface}"
4548

    
4549
EOD;
4550

    
4551
		file_put_contents($cron_file, $cron_cmd);
4552
		chmod($cron_file, 0700);
4553
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4554
	} else
4555
		unlink_if_exists($cron_file);
4556
}
4557

    
4558
function get_interface_default_mtu($type = "ethernet") {
4559
	switch ($type) {
4560
	case "gre":
4561
		return 1476;
4562
		break;
4563
	case "gif":
4564
		return 1280;
4565
		break;
4566
	case "tun":
4567
	case "vlan":
4568
	case "tap":
4569
	case "ethernet":
4570
	default:
4571
		return 1500;
4572
		break;
4573
	}
4574

    
4575
	/* Never reached */
4576
	return 1500;
4577
}
4578

    
4579
function get_vip_descr($ipaddress) {
4580
	global $config;
4581

    
4582
	foreach ($config['virtualip']['vip'] as $vip) {
4583
		if ($vip['subnet'] == $ipaddress) {
4584
			return ($vip['descr']);
4585
		}
4586
	}
4587
	return "";
4588
}
4589

    
4590
function interfaces_staticarp_configure($if) {
4591
	global $config, $g;
4592
	if(isset($config['system']['developerspew'])) {
4593
		$mt = microtime();
4594
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4595
	}
4596

    
4597
	$ifcfg = $config['interfaces'][$if];
4598

    
4599
	if (empty($if) || empty($ifcfg['if']))
4600
		return 0;
4601

    
4602
	/* Enable staticarp, if enabled */
4603
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4604
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4605
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4606
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4607

    
4608
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4609
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4610

    
4611
			}
4612

    
4613
		}
4614
	} else {
4615
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4616
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4617
	}
4618

    
4619
	return 0;
4620
}
4621

    
4622
function get_failover_interface($interface) {
4623
	global $config;
4624
	/* shortcut to get_real_interface if we find it in the config */
4625
	if(is_array($config['interfaces'][$interface])) {
4626
		$wanif = get_real_interface($interface);
4627
		return $wanif;
4628
	}
4629

    
4630
	/* compare against gateway groups */
4631
	$a_groups = return_gateway_groups_array();
4632
	if(is_array($a_groups[$interface])) {
4633
		/* we found a gateway group, fetch the interface or vip */
4634
		if($a_groups[$interface][0]['vip'] <> "")
4635
			$wanif = $a_groups[$interface][0]['vip'];
4636
		else
4637
			$wanif = $a_groups[$interface][0]['int'];
4638
		
4639
		return $wanif;
4640
	}
4641
	/* fall through to get_real_interface */
4642
	$wanif = get_real_interface($interface);
4643
	return $wanif;
4644
}
4645

    
4646
?>
(26-26/66)