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
			$ip6 = get_interface_ipv6($interface);
1124
			if (is_ipaddrv6($ip6))
1125
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1126
			if ($destroy == true)
1127
				pfSense_interface_flags($realif, -IFF_UP);
1128
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1129
		}
1130
		break;
1131
	case "6rd":
1132
	case "6to4":
1133
		$realif = "stf0";
1134
		if(does_interface_exist("$realif")) {
1135
			$ip6 = get_interface_ipv6($interface);
1136
			if (is_ipaddrv6($ip6))
1137
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1138
			if ($destroy == true)
1139
				pfSense_interface_flags($realif, -IFF_UP);
1140
		}		
1141
		break;
1142
	default:
1143
		if(does_interface_exist("$realif")) {
1144
			$ip6 = get_interface_ipv6($interface);
1145
			if (is_ipaddrv6($ip6))
1146
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1147
			if ($destroy == true)
1148
				pfSense_interface_flags($realif, -IFF_UP);
1149
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1150
		}
1151
		break;
1152
	}
1153

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

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

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

    
1183
	return;
1184
}
1185

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

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

    
1194
	return false;
1195
}
1196

    
1197
function interfaces_ptpid_next() {
1198

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

    
1203
	return $ptpid;
1204
}
1205

    
1206
function getMPDCRONSettings($pppif) {
1207
	global $config;
1208

    
1209
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1210
	if (is_array($config['cron']['item'])) {
1211
		foreach ($config['cron']['item'] as $i => $item) {
1212
			if (stripos($item['command'], $cron_cmd_file) !== false)
1213
				return array("ID" => $i, "ITEM" => $item);
1214
		}
1215
	}
1216

    
1217
	return NULL;
1218
}
1219

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

    
1223
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1224
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1225

    
1226
	if (!is_array($config['cron']['item'])) 
1227
		$config['cron']['item'] = array(); 
1228

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

    
1239
	if (empty($itemhash)) 
1240
		$itemhash = array();
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;
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
			break;
1265
	        case "weekly":
1266
			$item['minute'] = "0";
1267
			$item['hour'] = "0";
1268
			$item['mday'] = "*";
1269
			$item['month'] = "*";
1270
			$item['wday'] = "0";
1271
			break;
1272
		case "daily":
1273
			$item['minute'] = "0";
1274
			$item['hour'] = "0";
1275
			$item['mday'] = "*";
1276
			$item['month'] = "*";
1277
			$item['wday'] = "*";
1278
			break;
1279
		case "hourly":
1280
			$item['minute'] = "0";
1281
			$item['hour'] = "*";
1282
			$item['mday'] = "*";
1283
			$item['month'] = "*";
1284
			$item['wday'] = "*";
1285
			break;
1286
		} // end switch
1287
		$item['who'] = "root";
1288
		$item['command'] = $cron_cmd_file;
1289
	}
1290
	if (empty($item))
1291
		return;
1292
	if (isset($item['ID'])) 
1293
		$config['cron']['item'][$item['ID']] = $item;
1294
	else 
1295
		$config['cron']['item'][] = $item;
1296
}
1297

    
1298
/*
1299
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1300
 * It writes the mpd config file to /var/etc every time the link is opened.
1301
 */
1302
function interface_ppps_configure($interface) {
1303
	global $config, $g;
1304

    
1305
	/* Return for unassigned interfaces. This is a minimum requirement. */
1306
	if (empty($config['interfaces'][$interface]))
1307
		return 0;
1308
	$ifcfg = $config['interfaces'][$interface];
1309
	if (!isset($ifcfg['enable']))
1310
		return 0;
1311

    
1312
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1313
	if(!is_dir("/var/spool/lock")) {
1314
		exec("/bin/mkdir -p /var/spool/lock");
1315
		exec("/bin/chmod a+rw /var/spool/lock/.");
1316
	}
1317
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1318
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1319
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1320

    
1321
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1322
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1323
			if ($ifcfg['if'] == $ppp['if'])
1324
				break;
1325
		}
1326
	}
1327
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1328
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1329
		return 0;
1330
	}
1331
	$pppif = $ifcfg['if'];
1332
	if ($ppp['type'] == "ppp")
1333
		$type = "modem";
1334
	else
1335
		$type = $ppp['type'];
1336
	$upper_type = strtoupper($ppp['type']);	
1337

    
1338
	if($g['booting']) {
1339
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1340
		echo "starting {$pppif} link...";
1341
		// Do not re-configure the interface if we are booting and it's already been started
1342
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1343
			return 0;
1344
	}
1345

    
1346
	$ports = explode(',',$ppp['ports']);
1347
	if ($type != "modem") {
1348
		foreach ($ports as $pid => $port)
1349
			$ports[$pid] = get_real_interface($port);
1350
	}
1351
	$localips = explode(',',$ppp['localip']);
1352
	$gateways = explode(',',$ppp['gateway']);
1353
	$subnets = explode(',',$ppp['subnet']);
1354

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

    
1419
		if (is_ipaddr($ppp['gateway']))
1420
			$gateway = $ppp['gateway'];
1421
		else
1422
			$gateway = "10.64.64.{$pppid}";
1423
		$ranges = "{$localip}/0 {$gateway}/0";
1424
		
1425
		if (empty($ppp['apnum']))	
1426
			$ppp['apnum'] = 1;
1427
	} else
1428
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1429

    
1430
	if (isset($ppp['ondemand'])) 
1431
		$ondemand = "enable";
1432
	else
1433
		$ondemand = "disable";
1434
	if (!isset($ppp['idletimeout']))
1435
		$ppp['idletimeout'] = 0;
1436

    
1437
	if (empty($ppp['username']) && $type == "modem"){
1438
		$ppp['username'] = "user";
1439
		$ppp['password'] = "none";
1440
	}
1441
	if (empty($ppp['password']) && $type == "modem")
1442
		$passwd = "none";
1443
	else
1444
		$passwd = base64_decode($ppp['password']);
1445

    
1446
	$bandwidths = explode(',',$ppp['bandwidth']);
1447
	$defaultmtu = "1492";
1448
	if (!empty($ifcfg['mtu']))
1449
		$defaultmtu = intval($ifcfg['mtu']);
1450
	$mtus = explode(',',$ppp['mtu']);
1451
	$mrus = explode(',',$ppp['mru']);
1452

    
1453
	if (isset($ppp['mrru']))
1454
		$mrrus = explode(',',$ppp['mrru']);
1455

    
1456
	// Construct the mpd.conf file
1457
	$mpdconf = <<<EOD
1458
startup:
1459
	# configure the console
1460
	set console close
1461
	# configure the web server
1462
	set web close
1463

    
1464
default:
1465
{$ppp['type']}client:
1466
	create bundle static {$interface}
1467
	set bundle enable ipv6cp
1468
	set iface name {$pppif}
1469

    
1470
EOD;
1471
	$setdefaultgw = false;
1472
	$founddefaultgw = false;
1473
	if (is_array($config['gateways']['gateway_item'])) {
1474
		foreach($config['gateways']['gateway_item'] as $gateway) {
1475
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1476
				$setdefaultgw = true;
1477
				break;
1478
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1479
				$founddefaultgw = true;
1480
				break;
1481
			}
1482
		}
1483
	}
1484
	
1485
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1486
		$setdefaultgw = true;
1487
		$mpdconf .= <<<EOD
1488
	set iface route default
1489

    
1490
EOD;
1491
	}
1492
	$mpdconf .= <<<EOD
1493
	set iface {$ondemand} on-demand
1494
	set iface idle {$ppp['idletimeout']}
1495

    
1496
EOD;
1497

    
1498
	if (isset($ppp['ondemand']))
1499
		$mpdconf .= <<<EOD
1500
	set iface addrs 10.10.1.1 10.10.1.2
1501

    
1502
EOD;
1503
	
1504
	if (isset($ppp['tcpmssfix']))
1505
		$tcpmss = "disable";
1506
	else
1507
		$tcpmss = "enable";
1508
		$mpdconf .= <<<EOD
1509
	set iface {$tcpmss} tcpmssfix
1510

    
1511
EOD;
1512

    
1513
	$mpdconf .= <<<EOD
1514
	set iface up-script /usr/local/sbin/ppp-linkup
1515
	set iface down-script /usr/local/sbin/ppp-linkdown
1516
	set ipcp ranges {$ranges}
1517

    
1518
EOD;
1519
	if (isset($ppp['vjcomp']))
1520
		$mpdconf .= <<<EOD
1521
	set ipcp no vjcomp
1522

    
1523
EOD;
1524

    
1525
	if (isset($config['system']['dnsallowoverride']))
1526
		$mpdconf .= <<<EOD
1527
	set ipcp enable req-pri-dns
1528
	set ipcp enable req-sec-dns
1529

    
1530
EOD;
1531
	if (!isset($ppp['verbose_log']))
1532
		$mpdconf .= <<<EOD
1533
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1534

    
1535
EOD;
1536
	foreach($ports as $pid => $port){
1537
		$port = get_real_interface($port);
1538
		$mpdconf .= <<<EOD
1539

    
1540
	create link static {$interface}_link{$pid} {$type}
1541
	set link action bundle {$interface}
1542
	set link {$multilink} multilink
1543
	set link keep-alive 10 60
1544
	set link max-redial 0
1545

    
1546
EOD;
1547
		if (isset($ppp['shortseq']))
1548
			$mpdconf .= <<<EOD
1549
	set link no shortseq
1550

    
1551
EOD;
1552

    
1553
		if (isset($ppp['acfcomp']))
1554
			$mpdconf .= <<<EOD
1555
	set link no acfcomp
1556

    
1557
EOD;
1558

    
1559
		if (isset($ppp['protocomp']))
1560
			$mpdconf .= <<<EOD
1561
	set link no protocomp
1562

    
1563
EOD;
1564

    
1565
		$mpdconf .= <<<EOD
1566
	set link disable chap pap
1567
	set link accept chap pap eap
1568
	set link disable incoming
1569

    
1570
EOD;
1571

    
1572

    
1573
		if (!empty($bandwidths[$pid]))
1574
			$mpdconf .= <<<EOD
1575
	set link bandwidth {$bandwidths[$pid]}
1576

    
1577
EOD;
1578

    
1579
		if (empty($mtus[$pid]))
1580
			$mtus[$pid] = $defaultmtu;
1581
			$mpdconf .= <<<EOD
1582
	set link mtu {$mtus[$pid]}
1583

    
1584
EOD;
1585

    
1586
		if (!empty($mrus[$pid]))
1587
			$mpdconf .= <<<EOD
1588
	set link mru {$mrus[$pid]}
1589

    
1590
EOD;
1591

    
1592
		if (!empty($mrrus[$pid]))
1593
			$mpdconf .= <<<EOD
1594
	set link mrru {$mrrus[$pid]}
1595

    
1596
EOD;
1597

    
1598
		$mpdconf .= <<<EOD
1599
	set auth authname "{$ppp['username']}"
1600
	set auth password {$passwd}
1601

    
1602
EOD;
1603
		if ($type == "modem") {
1604
			$mpdconf .= <<<EOD
1605
	set modem device {$ppp['ports']}
1606
	set modem script DialPeer
1607
	set modem idle-script Ringback
1608
	set modem watch -cd
1609
	set modem var \$DialPrefix "DT"
1610
	set modem var \$Telephone "{$ppp['phone']}"
1611

    
1612
EOD;
1613
		}
1614
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1615
			$mpdconf .= <<<EOD
1616
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1617

    
1618
EOD;
1619
		}
1620
		if (isset($ppp['initstr']) && $type == "modem") {
1621
			$initstr = base64_decode($ppp['initstr']);
1622
			$mpdconf .= <<<EOD
1623
	set modem var \$InitString "{$initstr}"
1624

    
1625
EOD;
1626
		}
1627
		if (isset($ppp['simpin']) && $type == "modem") {
1628
			if($ppp['pin-wait'] == "")
1629
				$ppp['pin-wait'] = 0;
1630
			$mpdconf .= <<<EOD
1631
	set modem var \$SimPin "{$ppp['simpin']}"
1632
	set modem var \$PinWait "{$ppp['pin-wait']}"
1633

    
1634
EOD;
1635
		}
1636
		if (isset($ppp['apn']) && $type == "modem") {
1637
			$mpdconf .= <<<EOD
1638
	set modem var \$APN "{$ppp['apn']}"
1639
	set modem var \$APNum "{$ppp['apnum']}"
1640

    
1641
EOD;
1642
		}
1643
		if ($type == "pppoe") {
1644
			// Send a null service name if none is set.
1645
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1646
			$mpdconf .= <<<EOD
1647
	set pppoe service "{$provider}"
1648

    
1649
EOD;
1650
		}
1651
		if ($type == "pppoe")
1652
			$mpdconf .= <<<EOD
1653
	set pppoe iface {$port}
1654

    
1655
EOD;
1656

    
1657
		if ($type == "pptp" || $type == "l2tp") {
1658
			$mpdconf .= <<<EOD
1659
	set {$type} self {$localips[$pid]}
1660
	set {$type} peer {$gateways[$pid]}
1661

    
1662
EOD;
1663
		}
1664
		
1665
		$mpdconf .= "\topen\n";
1666
	} //end foreach($port)
1667

    
1668

    
1669
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1670
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1671
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1672
	else {
1673
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1674
		if (!$fd) {
1675
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1676
			return 0;
1677
		}
1678
		// Write out mpd_ppp.conf
1679
		fwrite($fd, $mpdconf);
1680
		fclose($fd);
1681
		unset($mpdconf);
1682
	}
1683

    
1684
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1685
	if (isset($ppp['uptime'])) {
1686
		if (!file_exists("/conf/{$pppif}.log")) {
1687
			conf_mount_rw();
1688
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1689
			conf_mount_ro();
1690
		}
1691
	} else {
1692
		if (file_exists("/conf/{$pppif}.log")) {
1693
			conf_mount_rw();
1694
			mwexec("rm -f /conf/{$pppif}.log");
1695
			conf_mount_ro();
1696
		}
1697
	}
1698

    
1699
	/* clean up old lock files */
1700
	foreach($ports as $port) {
1701
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1702
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1703
	}
1704

    
1705
	/* fire up mpd */
1706
	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");
1707

    
1708
	// Check for PPPoE periodic reset request 
1709
	if ($type == "pppoe") {
1710
		if (!empty($ppp['pppoe-reset-type']))
1711
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1712
		else
1713
			interface_setup_pppoe_reset_file($ppp['if']);
1714
	}
1715
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1716
	$i = 0;
1717
	while($i < 10) {
1718
		exec("/sbin/ifconfig {$ppp['if']} 2>&1", $out, $ret);
1719
		if($ret == 0)
1720
			break;
1721
		sleep(1);
1722
		$i++;
1723
	}
1724

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

    
1743
	return 1;
1744
}
1745

    
1746
function interfaces_carp_setup() {
1747
	global $g, $config;
1748

    
1749
	$balanacing = "";
1750
	$pfsyncinterface = "";
1751
	$pfsyncenabled = "";
1752
	if(isset($config['system']['developerspew'])) {
1753
		$mt = microtime();
1754
		echo "interfaces_carp_setup() being called $mt\n";
1755
	}
1756

    
1757
	// Prepare CmdCHAIN that will be used to execute commands.
1758
	$cmdchain = new CmdCHAIN();	
1759

    
1760
	if ($g['booting']) {
1761
		echo gettext("Configuring CARP settings...");
1762
		mute_kernel_msgs();
1763
	}
1764

    
1765
	/* suck in configuration items */
1766
	if($config['hasync']) {
1767
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1768
		$balanacing = $config['hasync']['balancing'];
1769
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1770
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1771
	} else {
1772
		unset($pfsyncinterface);
1773
		unset($balanacing);
1774
		unset($pfsyncenabled);
1775
	}
1776

    
1777
	if($balanacing) {
1778
		$cmdchain->add(gettext("Enable CARP ARP-balancing"), "/sbin/sysctl net.inet.carp.arpbalance=1", true);
1779
		$cmdchain->add(gettext("Disallow CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=0", true);
1780
	} else
1781
		$cmdchain->add(gettext("Enable CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=1", true);		
1782

    
1783
	$cmdchain->add(gettext("Enable CARP logging"), "/sbin/sysctl net.inet.carp.log=1", true);
1784
	if (!empty($pfsyncinterface))
1785
		$carp_sync_int = get_real_interface($pfsyncinterface);
1786

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

    
1802
	/* setup pfsync interface */
1803
	if($carp_sync_int and $pfsyncenabled) {
1804
		if (is_ipaddr($pfsyncpeerip))
1805
			$cmdchain->add(gettext("Bring up pfsync0 syncpeer"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} syncpeer {$pfsyncpeerip} up", false);						
1806
		else
1807
			$cmdchain->add(gettext("Bring up pfsync0 syncdev"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} up", false);			
1808
	} else
1809
		$cmdchain->add(gettext("Bring up pfsync0"), "/sbin/ifconfig pfsync0 syncdev lo0 up", false);						
1810

    
1811
	sleep(1);
1812

    
1813
	/* 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
1814
	 * for existing sessions.
1815
	 */
1816
	if ($config['hasync']['pfsyncenabled'] === "on"){
1817
		log_error("waiting for pfsync...");
1818
		$i = 0;
1819
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1820
			$i++;
1821
			sleep(1);
1822
		}
1823
		log_error("pfsync done in $i seconds.");
1824
		log_error("Configuring CARP settings finalize...");
1825
	}
1826

    
1827
	if($config['virtualip']['vip'])
1828
		$cmdchain->add(gettext("Allow CARP."), "/sbin/sysctl net.inet.carp.allow=1", true);				
1829
	else
1830
		$cmdchain->add(gettext("Disallow CARP."), "/sbin/sysctl net.inet.carp.allow=0", true);		
1831
	
1832
	if($g['debug'])
1833
		$cmdchain->setdebug(); // optional for verbose logging
1834

    
1835
	$cmdchain->execute();
1836
	$cmdchain->clear();
1837

    
1838
	if ($g['booting']) {
1839
		unmute_kernel_msgs();
1840
		echo gettext("done.") . "\n";
1841
	}
1842
}
1843

    
1844
function interface_proxyarp_configure($interface = "") {
1845
	global $config, $g;
1846
	if(isset($config['system']['developerspew'])) {
1847
		$mt = microtime();
1848
		echo "interface_proxyarp_configure() being called $mt\n";
1849
	}
1850

    
1851
	/* kill any running choparp */
1852
	if (empty($interface))
1853
		killbyname("choparp");
1854
	else {
1855
		$vipif = get_real_interface($interface);
1856
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1857
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1858
	}
1859

    
1860
	$paa = array();
1861
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1862

    
1863
		/* group by interface */
1864
		foreach ($config['virtualip']['vip'] as $vipent) {
1865
			if ($vipent['mode'] === "proxyarp") {
1866
				if ($vipent['interface'])
1867
					$proxyif = $vipent['interface'];
1868
				else
1869
					$proxyif = "wan";
1870
				
1871
				if (!empty($interface) && $interface != $proxyif)
1872
					continue;
1873

    
1874
				if (!is_array($paa[$proxyif]))
1875
					$paa[$proxyif] = array();
1876

    
1877
				$paa[$proxyif][] = $vipent;
1878
			}
1879
		}
1880
	}
1881

    
1882
	if (!empty($interface)) {
1883
		if (is_array($paa[$interface])) {
1884
			$paaifip = get_interface_ip($interface);
1885
                        if (!is_ipaddr($paaifip))
1886
                                return;
1887
                        $args = get_real_interface($interface) . " auto";
1888
                        foreach ($paa[$interface] as $paent) {
1889
                                if (isset($paent['subnet']))
1890
                                        $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1891
                                else if (isset($paent['range']))
1892
                                        $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1893
                        }
1894
                        mwexec_bg("/usr/local/sbin/choparp " . $args);	
1895
		}
1896
	} else if (count($paa) > 0) {
1897
		foreach ($paa as $paif => $paents)  {
1898
			$paaifip = get_interface_ip($paif);
1899
			if (!is_ipaddr($paaifip))
1900
				continue;
1901
			$args = get_real_interface($paif) . " auto";
1902
			foreach ($paents as $paent) {
1903
				if (isset($paent['subnet']))
1904
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1905
				else if (isset($paent['range']))
1906
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1907
			}
1908
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1909
		}
1910
	}
1911
}
1912

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

    
1952
function interface_ipalias_configure(&$vip) {
1953
	if ($vip['mode'] == "ipalias") {
1954
		$if = get_real_interface($vip['interface']);
1955
		$af = "inet";
1956
		if(is_ipaddrv6($vip['subnet']))
1957
			$af = "inet6";
1958
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
1959
	}
1960
}
1961

    
1962
function interface_reload_carps($cif) {
1963
	global $config;
1964

    
1965
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
1966
	if (empty($carpifs))
1967
		return;
1968

    
1969
	$carps = explode(" ", $carpifs);
1970
	if(is_array($config['virtualip']['vip'])) {
1971
		$viparr = &$config['virtualip']['vip'];
1972
		foreach ($viparr as $vip) {
1973
			if (in_array($vip['carpif'], $carps)) {
1974
				switch ($vip['mode']) {
1975
				case "carp":
1976
					interface_vip_bring_down($vip);
1977
					sleep(1);
1978
					interface_carp_configure($vip);
1979
					break;
1980
				case "ipalias":
1981
					interface_vip_bring_down($vip);
1982
					sleep(1);
1983
					interface_ipalias_configure($vip);
1984
					break;
1985
				}
1986
			}
1987
		}
1988
	}
1989
}
1990

    
1991
function interface_carp_configure(&$vip) {
1992
	global $config, $g;
1993
	if(isset($config['system']['developerspew'])) {
1994
		$mt = microtime();
1995
		echo "interface_carp_configure() being called $mt\n";
1996
	}
1997

    
1998
	if ($vip['mode'] != "carp")
1999
		return;
2000

    
2001
	/*
2002
	 * ensure the interface containing the VIP really exists
2003
 	 * prevents a panic if the interface is missing or invalid
2004
	 */
2005
	$realif = get_real_interface($vip['interface']);
2006
	if (!does_interface_exist($realif)) {
2007
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2008
		return;
2009
	}
2010

    
2011
	if(is_ipaddrv4($vip['subnet'])) {
2012
		/* Ensure CARP IP really exists prior to loading up. */
2013
		$ww_subnet_ip = find_interface_ip($realif);
2014
		$ww_subnet_bits = find_interface_subnet($realif);
2015
		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'])) {
2016
			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", "");
2017
			return;
2018
		}
2019
	}
2020
	if(is_ipaddrv6($vip['subnet'])) {
2021
		/* Ensure CARP IP really exists prior to loading up. */
2022
		$ww_subnet_ip = find_interface_ipv6($realif);
2023
		$ww_subnet_bits = find_interface_subnetv6($realif);
2024
		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'])) {
2025
			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", "");
2026
			return;
2027
		}
2028
	}
2029

    
2030
	// set the vip interface to the vhid
2031
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2032

    
2033
	/* create the carp interface and setup */
2034
	if (does_interface_exist($vipif)) {
2035
		pfSense_interface_flags($vipif, -IFF_UP);
2036
	} else {
2037
		$carpif = pfSense_interface_create("carp");
2038
		pfSense_interface_rename($carpif, $vipif);
2039
		pfSense_ngctl_name("{$carpif}:", $vipif);
2040
	}
2041

    
2042
	/* invalidate interface cache */
2043
	get_interface_arr(true);
2044

    
2045
	$vip_password = $vip['password'];
2046
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2047
	if ($vip['password'] != "")
2048
		$password = " pass {$vip_password}";
2049

    
2050
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2051
	$advbase = "";
2052
	if (!empty($vip['advbase']))
2053
		$advbase = "advbase {$vip['advbase']}";
2054

    
2055
	if(is_ipaddrv4($vip['subnet'])) {
2056
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2057
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2058
	}
2059
	if(is_ipaddrv6($vip['subnet'])) {
2060
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2061
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2062
	}
2063

    
2064
	interfaces_bring_up($vipif);
2065

    
2066
	return $vipif;
2067
}
2068

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

    
2110
	if($needs_clone == true) {
2111
		/* remove previous instance if it exists */
2112
		if(does_interface_exist($realif))
2113
			pfSense_interface_destroy($realif);
2114

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

    
2133
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2134
	global $config, $g;
2135

    
2136
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2137
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
2138
	                         'regdomain', 'regcountry', 'reglocation');
2139

    
2140
	if(!is_interface_wireless($ifcfg['if']))
2141
		return;
2142

    
2143
	$baseif = interface_get_wireless_base($ifcfg['if']);
2144

    
2145
	// Sync shared settings for assigned clones
2146
	$iflist = get_configured_interface_list(false, true);
2147
	foreach ($iflist as $if) {
2148
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2149
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2150
				foreach ($shared_settings as $setting) {
2151
					if ($sync_changes) {
2152
						if (isset($ifcfg['wireless'][$setting]))
2153
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2154
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2155
							unset($config['interfaces'][$if]['wireless'][$setting]);
2156
					} else {
2157
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2158
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2159
						else if (isset($ifcfg['wireless'][$setting]))
2160
							unset($ifcfg['wireless'][$setting]);
2161
					}
2162
				}
2163
				if (!$sync_changes)
2164
					break;
2165
			}
2166
		}
2167
	}
2168

    
2169
	// Read or write settings at shared area
2170
	if (isset($config['wireless']['interfaces'][$baseif])) {
2171
		foreach ($shared_settings as $setting) {
2172
			if ($sync_changes) {
2173
				if (isset($ifcfg['wireless'][$setting]))
2174
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2175
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2176
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2177
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2178
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2179
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2180
				else if (isset($ifcfg['wireless'][$setting]))
2181
					unset($ifcfg['wireless'][$setting]);
2182
			}
2183
		}
2184
	}
2185

    
2186
	// Sync the mode on the clone creation page with the configured mode on the interface
2187
	if (interface_is_wireless_clone($ifcfg['if'])) {
2188
		foreach ($config['wireless']['clone'] as &$clone) {
2189
			if ($clone['cloneif'] == $ifcfg['if']) {
2190
				if ($sync_changes) {
2191
					$clone['mode'] = $ifcfg['wireless']['mode'];
2192
				} else {
2193
					$ifcfg['wireless']['mode'] = $clone['mode'];
2194
				}
2195
				break;
2196
			}
2197
		}
2198
		unset($clone);
2199
	}
2200
}
2201

    
2202
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2203
	global $config, $g;
2204

    
2205
	/*    open up a shell script that will be used to output the commands.
2206
	 *    since wireless is changing a lot, these series of commands are fragile
2207
	 *    and will sometimes need to be verified by a operator by executing the command
2208
	 *    and returning the output of the command to the developers for inspection.  please
2209
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2210
	 */
2211

    
2212
	// Remove script file
2213
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2214

    
2215
	// Clone wireless nic if needed.
2216
	interface_wireless_clone($if, $wl);
2217

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

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

    
2225
	/* set values for /path/program */
2226
	$hostapd = "/usr/sbin/hostapd";
2227
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2228
	$ifconfig = "/sbin/ifconfig";
2229
	$sysctl = "/sbin/sysctl";
2230
	$killall = "/usr/bin/killall";
2231

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

    
2234
	$wlcmd = array();
2235
	$wl_sysctl = array();
2236
	/* Make sure it's up */
2237
	$wlcmd[] = "up";
2238
	/* Set a/b/g standard */
2239
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2240
	$wlcmd[] = "mode " . escapeshellarg($standard);
2241

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

    
2247
	/* Set ssid */
2248
	if($wlcfg['ssid'])
2249
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2250

    
2251
	/* Set 802.11g protection mode */
2252
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2253

    
2254
	/* set wireless channel value */
2255
	if(isset($wlcfg['channel'])) {
2256
		if($wlcfg['channel'] == "0") {
2257
			$wlcmd[] = "channel any";
2258
		} else {
2259
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2260
		}
2261
	}
2262

    
2263
	/* Set antenna diversity value */
2264
	if(isset($wlcfg['diversity']))
2265
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2266

    
2267
	/* Set txantenna value */
2268
	if(isset($wlcfg['txantenna']))
2269
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2270

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

    
2275
	/* set Distance value */
2276
	if($wlcfg['distance'])
2277
		$distance = escapeshellarg($wlcfg['distance']);
2278

    
2279
	/* Set wireless hostap mode */
2280
	if ($wlcfg['mode'] == "hostap") {
2281
		$wlcmd[] = "mediaopt hostap";
2282
	} else {
2283
		$wlcmd[] = "-mediaopt hostap";
2284
	}
2285

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

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

    
2295
	/* handle hide ssid option */
2296
	if(isset($wlcfg['hidessid']['enable'])) {
2297
		$wlcmd[] = "hidessid";
2298
	} else {
2299
		$wlcmd[] = "-hidessid";
2300
	}
2301

    
2302
	/* handle pureg (802.11g) only option */
2303
	if(isset($wlcfg['pureg']['enable'])) {
2304
		$wlcmd[] = "mode 11g pureg";
2305
	} else {
2306
		$wlcmd[] = "-pureg";
2307
	}
2308

    
2309
	/* handle puren (802.11n) only option */
2310
	if(isset($wlcfg['puren']['enable'])) {
2311
		$wlcmd[] = "puren";
2312
	} else {
2313
		$wlcmd[] = "-puren";
2314
	}
2315

    
2316
	/* enable apbridge option */
2317
	if(isset($wlcfg['apbridge']['enable'])) {
2318
		$wlcmd[] = "apbridge";
2319
	} else {
2320
		$wlcmd[] = "-apbridge";
2321
	}
2322

    
2323
	/* handle turbo option */
2324
	if(isset($wlcfg['turbo']['enable'])) {
2325
		$wlcmd[] = "mediaopt turbo";
2326
	} else {
2327
		$wlcmd[] = "-mediaopt turbo";
2328
	}
2329

    
2330
	/* handle txpower setting */
2331
	/* if($wlcfg['txpower'] <> "")
2332
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2333
	*/
2334
	/* handle wme option */
2335
	if(isset($wlcfg['wme']['enable'])) {
2336
		$wlcmd[] = "wme";
2337
	} else {
2338
		$wlcmd[] = "-wme";
2339
	}
2340

    
2341
	/* set up wep if enabled */
2342
	$wepset = "";
2343
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2344
		switch($wlcfg['wpa']['auth_algs']) {
2345
			case "1":
2346
				$wepset .= "authmode open wepmode on ";
2347
				break;
2348
			case "2":
2349
				$wepset .= "authmode shared wepmode on ";
2350
				break;
2351
			case "3":
2352
				$wepset .= "authmode mixed wepmode on ";
2353
		}
2354
		$i = 1;
2355
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2356
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2357
			if (isset($wepkey['txkey'])) {
2358
				$wlcmd[] = "weptxkey {$i} ";
2359
			}
2360
			$i++;
2361
		}
2362
		$wlcmd[] = $wepset;
2363
	} else {
2364
		$wlcmd[] = "authmode open wepmode off ";
2365
	}
2366

    
2367
	mwexec(kill_hostapd("{$if}"));
2368
	mwexec(kill_wpasupplicant("{$if}"));
2369

    
2370
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2371
	conf_mount_rw();
2372

    
2373
	switch ($wlcfg['mode']) {
2374
		case 'bss':
2375
			if (isset($wlcfg['wpa']['enable'])) {
2376
				$wpa .= <<<EOD
2377
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2378
ctrl_interface_group=0
2379
ap_scan=1
2380
#fast_reauth=1
2381
network={
2382
ssid="{$wlcfg['ssid']}"
2383
scan_ssid=1
2384
priority=5
2385
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2386
psk="{$wlcfg['wpa']['passphrase']}"
2387
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2388
group={$wlcfg['wpa']['wpa_pairwise']}
2389
}
2390
EOD;
2391

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

    
2427
EOD;
2428

    
2429
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2430
	$wpa .= <<<EOD
2431
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2432
rsn_preauth=1
2433
rsn_preauth_interfaces={$if}
2434

    
2435
EOD;
2436

    
2437
}
2438
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2439
					$auth_server_port = "1812";
2440
					if($wlcfg['auth_server_port']) 
2441
						$auth_server_port = $wlcfg['auth_server_port'];
2442
					$auth_server_port2 = "1812";
2443
					if($wlcfg['auth_server_port2']) 
2444
						$auth_server_port2 = $wlcfg['auth_server_port2'];
2445
					$wpa .= <<<EOD
2446

    
2447
ieee8021x=1
2448
auth_server_addr={$wlcfg['auth_server_addr']}
2449
auth_server_port={$auth_server_port}
2450
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2451
auth_server_addr={$wlcfg['auth_server_addr2']}
2452
auth_server_port={$auth_server_port2}
2453
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2454

    
2455
EOD;
2456
				} else {
2457
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2458
				}
2459

    
2460
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2461
				fwrite($fd, "{$wpa}");
2462
				fclose($fd);
2463

    
2464
			}
2465
			break;
2466
	}
2467

    
2468
	/*
2469
	 *    all variables are set, lets start up everything
2470
	 */
2471

    
2472
	$baseif = interface_get_wireless_base($if);
2473
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2474
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2475

    
2476
	/* set sysctls for the wireless interface */
2477
	if (!empty($wl_sysctl)) {
2478
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2479
		foreach ($wl_sysctl as $wl_sysctl_line) {
2480
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2481
		}
2482
	}
2483

    
2484
	/* set ack timers according to users preference (if he/she has any) */
2485
	if($distance) {
2486
		fwrite($fd_set, "# Enable ATH distance settings\n");
2487
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2488
	}
2489

    
2490
	if (isset($wlcfg['wpa']['enable'])) {
2491
		if ($wlcfg['mode'] == "bss") {
2492
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2493
		}
2494
		if ($wlcfg['mode'] == "hostap") {
2495
			/* add line to script to restore old mac to make hostapd happy */
2496
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2497
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2498
				if (is_macaddr($if_oldmac))
2499
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2500
						" link " . escapeshellarg($if_oldmac) . "\n");
2501
			}
2502

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

    
2505
			/* add line to script to restore spoofed mac after running hostapd */
2506
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2507
				if ($wl['spoofmac'])
2508
					$if_curmac = $wl['spoofmac'];
2509
				else
2510
					$if_curmac = get_interface_mac($if);
2511
				if (is_macaddr($if_curmac))
2512
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2513
						" link " . escapeshellarg($if_curmac) . "\n");
2514
			}
2515
		}
2516
	}
2517

    
2518
	fclose($fd_set);
2519
	conf_mount_ro();
2520

    
2521
	/* Making sure regulatory settings have actually changed
2522
	 * before applying, because changing them requires bringing
2523
	 * down all wireless networks on the interface. */
2524
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2525
	$ifconfig_str = implode($output);
2526
	unset($output);
2527
	$reg_changing = false;
2528

    
2529
	/* special case for the debug country code */
2530
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2531
		$reg_changing = true;
2532
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2533
		$reg_changing = true;
2534
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2535
		$reg_changing = true;
2536
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2537
		$reg_changing = true;
2538
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2539
		$reg_changing = true;
2540

    
2541
	if ($reg_changing) {
2542
		/* set regulatory domain */
2543
		if($wlcfg['regdomain'])
2544
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2545

    
2546
		/* set country */
2547
		if($wlcfg['regcountry'])
2548
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2549

    
2550
		/* set location */
2551
		if($wlcfg['reglocation'])
2552
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2553

    
2554
		$wlregcmd_args = implode(" ", $wlregcmd);
2555

    
2556
		/* build a complete list of the wireless clones for this interface */
2557
		$clone_list = array();
2558
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2559
			$clone_list[] = interface_get_wireless_clone($baseif);
2560
		if (is_array($config['wireless']['clone'])) {
2561
			foreach ($config['wireless']['clone'] as $clone) {
2562
				if ($clone['if'] == $baseif)
2563
					$clone_list[] = $clone['cloneif'];
2564
			}
2565
		}
2566

    
2567
		/* find which clones are up and bring them down */
2568
		$clones_up = array();
2569
		foreach ($clone_list as $clone_if) {
2570
			$clone_status = pfSense_get_interface_addresses($clone_if);
2571
			if ($clone_status['status'] == 'up') {
2572
				$clones_up[] = $clone_if;
2573
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2574
			}
2575
		}
2576

    
2577
		/* apply the regulatory settings */
2578
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2579

    
2580
		/* bring the clones back up that were previously up */
2581
		foreach ($clones_up as $clone_if) {
2582
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2583

    
2584
			/*
2585
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2586
			 * is in infrastructure mode, and WPA is enabled.
2587
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2588
			 */
2589
			if ($clone_if != $if) {
2590
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2591
				if ( !empty($friendly_if)
2592
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2593
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2594
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2595
				}
2596
			}
2597
		}
2598
	}
2599

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

    
2604
	/* configure wireless */
2605
	$wlcmd_args = implode(" ", $wlcmd);
2606
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2607

    
2608
	
2609
	sleep(1);
2610
	/* execute hostapd and wpa_supplicant if required in shell */
2611
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2612

    
2613
	return 0;
2614

    
2615
}
2616

    
2617
function kill_hostapd($interface) {
2618
	return "/bin/pkill -f \"hostapd .*{$interface}\"\n";
2619
}
2620

    
2621
function kill_wpasupplicant($interface) {
2622
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\"\n";
2623
}
2624

    
2625
function find_dhclient_process($interface) {
2626
	if ($interface)
2627
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2628
	else
2629
		$pid = 0;
2630

    
2631
	return intval($pid);
2632
}
2633

    
2634
function find_dhcp6c_process($interface) {
2635
	if ($interface)
2636
		$pid = `/bin/ps auxww|grep "[d]hclient[ ]-6" |grep "{$interface}"|awk '{print $2}'`;
2637
	else
2638
		return(false);
2639

    
2640
	return intval($pid);
2641
}
2642

    
2643
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2644
	global $config, $g;
2645
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2646
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2647

    
2648
	$wancfg = $config['interfaces'][$interface];
2649

    
2650
	$realif = get_real_interface($interface);
2651
	$realhwif_array = get_parent_interface($interface);
2652
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2653
	$realhwif = $realhwif_array[0];
2654

    
2655
	/* Disable Accepting router advertisements unless specifically requested */
2656
	log_error("Deny router advertisements for interface {$interface}");
2657
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2658
			
2659
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2660
		/* remove all IPv4 and IPv6 addresses */
2661
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0);
2662
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -alias", true) == 0);
2663

    
2664
		/* only bring down the interface when both v4 and v6 are set to NONE */
2665
		if(($wancfg['ipaddr'] <> "none") && ($wancfg['ipaddrv6'] <> "none")) {
2666
			interface_bring_down($interface);
2667
		}
2668
	}
2669

    
2670
	/* wireless configuration? */
2671
	if (is_array($wancfg['wireless']))
2672
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2673

    
2674
	$mac = get_interface_mac($realhwif);
2675
	/*	Don't try to reapply the spoofed MAC if it's already applied.
2676
		When ifconfig link is used, it cycles the interface down/up, which triggers 
2677
		the interface config again, which attempts to spoof the MAC again, 
2678
		which cycles the link again... */
2679
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2680
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2681
			" link " . escapeshellarg($wancfg['spoofmac']));
2682

    
2683
                /*
2684
                 * All vlans need to spoof their parent mac address, too.  see
2685
                 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2686
                 */
2687
                if (is_array($config['vlans']['vlan'])) {
2688
                        foreach ($config['vlans']['vlan'] as $vlan) {
2689
                                if ($vlan['if'] == $realhwif)
2690
                                        mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2691
                                                " link " . escapeshellarg($wancfg['spoofmac']));
2692
                        }
2693
                }
2694
	}  else {
2695

    
2696
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2697
			/*   this is not a valid mac address.  generate a
2698
			 *   temporary mac address so the machine can get online.
2699
			 */
2700
			echo gettext("Generating new MAC address.");
2701
			$random_mac = generate_random_mac_address();
2702
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2703
				" link " . escapeshellarg($random_mac));
2704
			$wancfg['spoofmac'] = $random_mac;
2705
			write_config();
2706
			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");
2707
		}
2708
	}
2709

    
2710
	/* media */
2711
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2712
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2713
		if ($wancfg['media'])
2714
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2715
		if ($wancfg['mediaopt'])
2716
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2717
		mwexec($cmd);
2718
	}
2719
	if (!empty($wancfg['mtu']))
2720
		pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2721
	else {
2722
		$mtu = get_interface_default_mtu(remove_numbers($realhwif));
2723
		if ($mtu != get_interface_mtu($realhwif))
2724
			pfSense_interface_mtu($realhwif, $mtu);
2725
	}
2726

    
2727
	$options = pfSense_get_interface_addresses($realhwif);
2728
	if (is_array($options) && isset($options['caps']['polling'])) {
2729
		if (isset($config['system']['polling']))
2730
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2731
		else
2732
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2733
	}
2734

    
2735
	/* skip vlans for checksumming and polling */
2736
        if (!stristr($realhwif, "vlan") && is_array($options)) {
2737
		$flags = 0;
2738
		if(isset($config['system']['disablechecksumoffloading'])) {
2739
			if (isset($options['encaps']['txcsum']))
2740
				$flags |= IFCAP_TXCSUM;
2741
			if (isset($options['encaps']['rxcsum']))
2742
				$flags |= IFCAP_RXCSUM;
2743
        	} else {
2744
 			if (!isset($options['caps']['txcsum']))
2745
				$flags |= IFCAP_TXCSUM;
2746
			if (!isset($options['caps']['rxcsum']))
2747
				$flags |= IFCAP_RXCSUM;
2748
        	}
2749

    
2750
        	if(isset($config['system']['disablesegmentationoffloading'])) {
2751
                	if (isset($options['encaps']['tso4']))
2752
				$flags |= IFCAP_TSO;
2753
                	if (isset($options['encaps']['tso6']))
2754
				$flags |= IFCAP_TSO;
2755
        	} else {
2756
                	if (!isset($options['caps']['tso4']))
2757
				$flags |= IFCAP_TSO;
2758
                	if (!isset($options['caps']['tso6']))
2759
				$flags |= IFCAP_TSO;
2760
        	}
2761

    
2762
        	if(isset($config['system']['disablelargereceiveoffloading'])) {
2763
                	if (isset($options['encaps']['lro']))
2764
				$flags |= IFCAP_LRO;
2765
        	} else {
2766
                	if (!isset($options['caps']['lro']))
2767
				$flags |= IFCAP_LRO;
2768
        	}
2769

    
2770
        	/* if the NIC supports polling *AND* it is enabled in the GUI */
2771
        	if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2772
			$flags |= IFCAP_POLLING;
2773
		}
2774
               	pfSense_interface_capabilities($realhwif, -$flags);
2775
	}
2776

    
2777
	/* invalidate interface/ip/sn cache */
2778
	get_interface_arr(true);
2779
	unset($interface_ip_arr_cache[$realif]);
2780
	unset($interface_sn_arr_cache[$realif]);
2781
	unset($interface_ipv6_arr_cache[$realif]);
2782
	unset($interface_snv6_arr_cache[$realif]);
2783

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

    
2815
	switch ($wancfg['ipaddrv6']) {
2816
		case 'slaac':
2817
		case 'dhcp6':
2818
			interface_dhcpv6_configure($interface);
2819
			break;
2820
		case '6rd':
2821
			interface_6rd_configure($interface);
2822
			break;
2823
		case '6to4':
2824
			interface_6to4_configure($interface);
2825
			break;
2826
		case 'track6':
2827
			interface_track6_configure($interface);
2828
			break;
2829
		default:
2830
			if (is_ipaddr($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
2831
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
2832
				// FIXME: Add IPv6 Support to the pfSense module
2833
				mwexec("/sbin/ifconfig {$realif} inet6 {$wancfg['ipaddrv6']} prefixlen {$wancfg['subnetv6']} ");
2834
			}
2835
			break;
2836
	}
2837

    
2838
	if(does_interface_exist($wancfg['if']))
2839
		interfaces_bring_up($wancfg['if']);
2840

    
2841
	interface_netgraph_needed($interface);
2842
 	
2843
	if (!$g['booting']) {
2844
		link_interface_to_vips($interface, "update");
2845

    
2846
		unset($gre);
2847
		$gre = link_interface_to_gre($interface);
2848
		if (!empty($gre))
2849
			array_walk($gre, 'interface_gre_configure');
2850

    
2851
		unset($gif);
2852
		$gif = link_interface_to_gif($interface);
2853
		if (!empty($gif))
2854
			array_walk($gif, 'interface_gif_configure');
2855

    
2856
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
2857
			unset($bridgetmp);
2858
			$bridgetmp = link_interface_to_bridge($interface);
2859
			if (!empty($bridgetmp))
2860
				interface_bridge_add_member($bridgetmp, $realif);
2861
		}
2862

    
2863
		$grouptmp = link_interface_to_group($interface);
2864
		if (!empty($grouptmp))
2865
			array_walk($grouptmp, 'interface_group_add_member');
2866

    
2867
		if ($interface == "lan")
2868
			/* make new hosts file */
2869
			system_hosts_generate();
2870

    
2871
		if ($reloadall == true) {
2872

    
2873
			/* reconfigure static routes (kernel may have deleted them) */
2874
			system_routing_configure($interface);
2875

    
2876
			/* reload ipsec tunnels */
2877
			vpn_ipsec_configure();
2878

    
2879
			/* restart dnsmasq */
2880
			services_dnsmasq_configure();
2881

    
2882
			/* update dyndns */
2883
			send_event("service reload dyndns {$interface}");
2884

    
2885
			/* reload captive portal */
2886
			captiveportal_init_rules();
2887
		}
2888
	}
2889

    
2890
	return 0;
2891
}
2892

    
2893
function interface_track6_configure($interface = "lan") {
2894
	global $config, $g;
2895
	$iflist = get_configured_interface_with_descr(false, true);
2896

    
2897
	$wancfg = $config['interfaces'][$interface];
2898
	$wanif = $wancfg['if'];
2899
	if (empty($wancfg))
2900
		$wancfg = array();
2901

    
2902
	$wanif = get_real_interface($interface);
2903
	
2904
	/* If the interface is not configured via another, exit */
2905
	if(!$wancfg['track6-interface'] <> "") {
2906
		return(false);
2907
	}
2908

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

    
2913
	$type = $config['interfaces'][$wancfg['track6-interface']]['ipaddrv6'];
2914
	switch($type) {
2915
		case "6to4":
2916
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2917
			interface_track6_6to4_configure($interface);
2918
			break;
2919
		case "6rd":
2920
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2921
			interface_track6_6rd_configure($interface);
2922
			break;
2923
		case "dhcp6":
2924
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2925
			interface_track6_dhcp6_configure($interface);
2926
			break;
2927
		default:
2928
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']} but unknown type {$type}");
2929
			break;
2930
	}
2931
	return 0;
2932
}
2933

    
2934

    
2935
function interface_track6_6rd_configure($interface = "lan") {
2936
	global $config, $g;
2937
	$iflist = get_configured_interface_with_descr(false, true);
2938

    
2939
	$lancfg = $config['interfaces'][$interface];
2940
	$lanif = $lancfg['if'];
2941
	if (empty($lancfg))
2942
		$lancfg = array();
2943

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

    
2970
	/* binary presentation of the prefix for all 128 bits. */
2971
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
2972
	
2973
	/* just save the left prefix length bits */
2974
	$rd6lanbin = substr($rd6lanbin, 0, $rd6prefixlen);
2975
	/* add the v4 address, offset n bits from the left */
2976
	$rd6lanbin .= substr(sprintf("%032b", hexdec($hexwanv4)), (0 + $wancfg['prefix-6rd-v4plen']), 32);
2977

    
2978
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
2979
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
2980
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
2981
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
2982
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
2983
	/* fill the rest out with zeros */
2984
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
2985

    
2986
	/* convert the 128 bits for the lan address back into a valid IPv6 address */ 
2987
	$rd6lan = convert_128bit_to_ipv6($rd6lanbin) ."1";
2988
	
2989
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
2990
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
2991
	return 0;
2992
}
2993

    
2994
function interface_track6_6to4_configure($interface = "lan") {
2995
	global $config, $g;
2996
	$iflist = get_configured_interface_with_descr(false, true);
2997

    
2998
	$lancfg = $config['interfaces'][$interface];
2999
	$lanif = $lancfg['if'];
3000
	if (empty($lancfg))
3001
		$lancfg = array();
3002

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

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

    
3049
function interface_track6_dhcp6_configure($interface = "lan") {
3050
	global $config, $g;
3051
	$iflist = get_configured_interface_with_descr(false, true);
3052

    
3053
	$lancfg = $config['interfaces'][$interface];
3054
	$lanif = $lancfg['if'];
3055
	if (empty($lancfg))
3056
		$lancfg = array();
3057

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

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

    
3100
function interface_6rd_configure($interface = "wan") {
3101
	global $config, $g;
3102
	$iflist = get_configured_interface_with_descr(false, true);
3103

    
3104
	/* because this is a tunnel interface we can only function 
3105
	 *	with a public IPv4 address on the interface */
3106

    
3107
	$wancfg = $config['interfaces'][$interface];
3108
	$wanif = $wancfg['if'];
3109
	if (empty($wancfg))
3110
		$wancfg = array();
3111

    
3112
	$wanif = get_real_interface($interface);
3113
	
3114
	$ip4address = find_interface_ip($wanif);
3115
	$ip4gateway = get_interface_gateway($wanif);
3116
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3117
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3118
		return false;
3119
	}
3120
	$hexwanv4 = return_hex_ipv4($ip4address);
3121
	
3122
	if(!is_numeric($wancfg['prefix-6rd-v4plen']))
3123
		$wancfg['prefix-6rd-v4plen'] = 0;
3124

    
3125
	/* create the long prefix notation for math, save the prefix length */
3126
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3127
	$rd6prefixlen = $rd6prefix[1];
3128
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3129

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

    
3143
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3144
	$rd6brgw = convert_128bit_to_ipv6($rd6brprefixbin);
3145

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

    
3153
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3154
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3155

    
3156
	/* stf approach only works when embedding the entire 32 bits of the v4 */
3157
	mwexec("/sbin/ifconfig stf0 create");
3158
	mwexec("/sbin/ifconfig stf0 inet6 {$rd6prefix}/{$rd6prefixlen}");
3159
	log_error("Created 6rd interface stf0 {$rd6prefix}/{$rd6prefixlen}");
3160

    
3161
	/* write out a default router file */
3162
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3163
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3164

    
3165
	if (is_ipaddrv4($ip4gateway))
3166
		mwexec("route change -host " . $wancfg['gateway-6rd'] . " {$ip4gateway}");
3167

    
3168
	/* configure dependent interfaces */
3169
	foreach($iflist as $if => $ifname) {
3170
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3171
			interface_track6_configure($if);
3172
	}
3173

    
3174
	return 0;
3175
}
3176

    
3177
function interface_6to4_configure($interface = "wan"){
3178
	global $config, $g;
3179
	$iflist = get_configured_interface_with_descr(false, true);
3180

    
3181
	/* because this is a tunnel interface we can only function 
3182
	 *	with a public IPv4 address on the interface */
3183

    
3184
	$wancfg = $config['interfaces'][$interface];
3185
	$wanif = $wancfg['if'];
3186
	if (empty($wancfg))
3187
		$wancfg = array();
3188

    
3189
	$wanif = get_real_interface($interface);
3190
	
3191
	$ip4address = find_interface_ip($wanif);
3192
	$ip4gateway = get_interface_gateway($wanif);
3193
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3194
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3195
		return false;
3196
	}
3197
	
3198
	/* create the long prefix notation for math, save the prefix length */
3199
	$stfprefixlen = 16;
3200
	$stfprefix = Net_IPv6::uncompress("2002::");
3201
	$stfarr = explode(":", $stfprefix);
3202
	$v4prefixlen = "0";
3203
	
3204
	/* we need the hex form of the interface IPv4 address */
3205
	$ip4arr = explode(".", $ip4address);
3206
	$hexwanv4 = "";
3207
	foreach($ip4arr as $octet)
3208
		$hexwanv4 .= sprintf("%02x", $octet);
3209

    
3210
	/* we need the hex form of the broker IPv4 address */
3211
	$ip4arr = explode(".", "192.88.99.1");
3212
	$hexbrv4 = "";
3213
	foreach($ip4arr as $octet)
3214
		$hexbrv4 .= sprintf("%02x", $octet);
3215
	
3216
	/* binary presentation of the prefix for all 128 bits. */
3217
	$stfprefixbin = "";
3218
	foreach($stfarr as $element) {
3219
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3220
	}
3221
	/* just save the left prefix length bits */
3222
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3223

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

    
3228
	/* for the local subnet too. */
3229
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3230
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3231

    
3232
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3233
	$stfbrarr = array();
3234
	$stfbrbinarr = array();
3235
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3236
	foreach($stfbrbinarr as $bin)
3237
		$stfbrarr[] = dechex(bindec($bin));
3238
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3239

    
3240
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3241
	$stflanarr = array();
3242
	$stflanbinarr = array();
3243
	$stflanbinarr = str_split($stflanbin, 16);
3244
	foreach($stflanbinarr as $bin)
3245
		$stflanarr[] = dechex(bindec($bin));
3246
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3247
	$stflanarr[7] = 1;
3248
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3249

    
3250
	/* setup the stf interface */
3251
	mwexec("/sbin/ifconfig stf0 destroy");
3252
	mwexec("/sbin/ifconfig stf0 create");
3253
	mwexec("/sbin/ifconfig stf0 inet6 {$stflanpr} prefixlen 16");
3254

    
3255
	log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for stf0, route {$stfbrgw}");
3256
	
3257
	/* write out a default router file */
3258
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3259
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3260

    
3261
	if (is_ipaddrv4($ip4gateway)) {
3262
		mwexec("route change -host 192.88.99.1 {$ip4gateway}");
3263
	}
3264

    
3265
	/* configure dependent interfaces */
3266
	foreach($iflist as $if => $ifname) {
3267
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3268
			interface_track6_configure($if);
3269
	}
3270
	
3271
	return 0;
3272
}
3273

    
3274
function interface_dhcpv6_configure($interface = "wan") {
3275
	global $config, $g;
3276
	$iflist = get_configured_interface_with_descr(false, true);
3277

    
3278
	$wancfg = $config['interfaces'][$interface];
3279
	$wanif = $wancfg['if'];
3280
	if (empty($wancfg))
3281
		$wancfg = array();
3282

    
3283
	$wanif = get_real_interface($interface);
3284

    
3285
	/* Add ISC IPv6 dhclient here */
3286
	$fd = fopen("{$g['varetc_path']}/dhcp6c_{$interface}.conf", "w");
3287
	if (!$fd) {
3288
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3289
		return 1;
3290
	}
3291

    
3292
	$dhcp6cconf = "interface \"{$wanif}\" {\n";
3293
	$dhcp6cconf .= "script \"/sbin/dhclient6-script\";\n";
3294
	$dhcp6cconf .= "}\n";
3295

    
3296
	fwrite($fd, $dhcp6cconf);
3297
	fclose($fd);
3298

    
3299
	/* accept router advertisements for this interface */
3300
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3301
	log_error("Accept router advertisements on interface {$wanif} ");
3302
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3303

    
3304
	/* run a filter configure so that the filter rules allow traffic before we launch the client */
3305
	filter_configure_sync();
3306
	sleep(3);
3307

    
3308
	/* dhclient -6
3309
	 * -T temprorary address
3310
	 * -S information only
3311
	 * -P Prefix
3312
	 * -N request address with temporary or prefix
3313
	*/
3314

    
3315
	$dhcp6c_options = "";
3316
	if($wancfg['ipaddrv6'] == "slaac") {
3317
		$dhcp6c_options .= "-S ";
3318
	}
3319
	if($wancfg['ipaddrv6'] == "dhcp6") {
3320
		$dhcp6c_options .= "-N ";
3321
	}
3322
	if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3323
		$dhcp6c_options .= "-P ";		
3324
	}
3325
	/* fire up dhcp6c for IPv6 first, this backgrounds immediately */
3326
	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}");
3327
	sleep(5);
3328
	return 0;
3329
}
3330

    
3331
function interface_dhcp_configure($interface = "wan") {
3332
	global $config, $g;
3333

    
3334
	$wancfg = $config['interfaces'][$interface];
3335
	$wanif = $wancfg['if'];
3336
	if (empty($wancfg))
3337
		$wancfg = array();
3338

    
3339
	/* generate dhclient_wan.conf */
3340
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3341
	if (!$fd) {
3342
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3343
		return 1;
3344
	}
3345

    
3346
	if ($wancfg['dhcphostname']) {
3347
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3348
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3349
	} else {
3350
		$dhclientconf_hostname = "";
3351
	}
3352

    
3353
	$wanif = get_real_interface($interface);
3354
	if (empty($wanif)) {
3355
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3356
		return 0;
3357
	}
3358
 	$dhclientconf = "";
3359
	
3360
	$dhclientconf .= <<<EOD
3361
interface "{$wanif}" {
3362
timeout 60;
3363
retry 15;
3364
select-timeout 0;
3365
initial-interval 1;
3366
	{$dhclientconf_hostname}
3367
	script "/sbin/dhclient-script";
3368
}
3369

    
3370
EOD;
3371

    
3372
if(is_ipaddr($wancfg['alias-address'])) {
3373
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3374
	$dhclientconf .= <<<EOD
3375
alias {
3376
	interface  "{$wanif}";
3377
	fixed-address {$wancfg['alias-address']};
3378
	option subnet-mask {$subnetmask};
3379
}
3380

    
3381
EOD;
3382
}
3383
	fwrite($fd, $dhclientconf);
3384
	fclose($fd);
3385

    
3386
	/* bring wan interface up before starting dhclient */
3387
	if($wanif)
3388
		interfaces_bring_up($wanif);
3389
	else 
3390
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3391

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

    
3395
	return 0;
3396
}
3397

    
3398
function interfaces_group_setup() {
3399
	global $config;
3400

    
3401
	if (!is_array($config['ifgroups']['ifgroupentry']))
3402
		return;
3403

    
3404
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3405
		interface_group_setup($groupar);
3406

    
3407
	return;
3408
}
3409

    
3410
function interface_group_setup(&$groupname /* The parameter is an array */) {
3411
	global $config;
3412

    
3413
	if (!is_array($groupname))
3414
		return;
3415
	$members = explode(" ", $groupname['members']);
3416
	foreach($members as $ifs) {
3417
		$realif = get_real_interface($ifs);
3418
		if ($realif)
3419
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3420
	}
3421

    
3422
	return;
3423
}
3424

    
3425
function interface_group_add_member($interface, $groupname) {
3426
	$interface = get_real_interface($interface);
3427
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
3428
}
3429
 
3430
/* COMPAT Function */
3431
function convert_friendly_interface_to_real_interface_name($interface) {
3432
	return get_real_interface($interface);
3433
}
3434

    
3435
/* COMPAT Function */
3436
function get_real_wan_interface($interface = "wan") {
3437
	return get_real_interface($interface);
3438
}
3439

    
3440
/* COMPAT Function */
3441
function get_current_wan_address($interface = "wan") {
3442
	return get_interface_ip($interface);
3443
}
3444

    
3445
/*
3446
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3447
 */
3448
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3449
        global $config;
3450

    
3451
	if (stristr($interface, "_vip")) {
3452
                foreach ($config['virtualip']['vip'] as $counter => $vip) {
3453
                        if ($vip['mode'] == "carp")  {
3454
                                if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3455
                                        return $vip['interface'];
3456
                        }
3457
                }
3458
        }
3459

    
3460
        /* XXX: For speed reasons reference directly the interface array */
3461
	$ifdescrs = &$config['interfaces'];
3462
        //$ifdescrs = get_configured_interface_list(false, true);
3463

    
3464
        foreach ($ifdescrs as $if => $ifname) {
3465
                if ($config['interfaces'][$if]['if'] == $interface)
3466
                        return $if;
3467

    
3468
                if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
3469
                        return $if;
3470

    
3471
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
3472
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
3473
		/*
3474
                $int = get_parent_interface($if);
3475
                if ($int[0] == $interface)
3476
                        return $ifname;
3477
		*/
3478
        }
3479
        return NULL;
3480
}
3481

    
3482
/* attempt to resolve interface to friendly descr */
3483
function convert_friendly_interface_to_friendly_descr($interface) {
3484
        global $config;
3485

    
3486
        switch ($interface) {
3487
        case "l2tp":
3488
        	$ifdesc = "L2TP";
3489
                break;
3490
	case "pptp":
3491
		$ifdesc = "PPTP";
3492
		break;
3493
	case "pppoe":
3494
		$ifdesc = "PPPoE";
3495
		break;
3496
	case "openvpn":
3497
		$ifdesc = "OpenVPN";
3498
		break;
3499
	case "enc0":
3500
	case "ipsec":
3501
		$ifdesc = "IPsec";
3502
		break;
3503
        default:
3504
                if (isset($config['interfaces'][$interface])) {
3505
                        if (empty($config['interfaces'][$interface]['descr']))
3506
                                $ifdesc = strtoupper($interface);
3507
                        else
3508
                                $ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3509
			break;
3510
		} else if (stristr($interface, "_vip")) {
3511
			if (is_array($config['virtualip']['vip'])) {
3512
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3513
					if ($vip['mode'] == "carp")  {
3514
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3515
							return "{$vip['subnet']} - {$vip['descr']}";
3516
					}
3517
				}
3518
                        }
3519
                } else {
3520
			/* if list */
3521
			$ifdescrs = get_configured_interface_with_descr(false, true);
3522
			foreach ($ifdescrs as $if => $ifname) {
3523
				if ($if == $interface || $ifname == $interface)
3524
					return $ifname;
3525
			}
3526
		}
3527
                break;
3528
        }
3529

    
3530
        return $ifdesc;
3531
}
3532

    
3533
function convert_real_interface_to_friendly_descr($interface) {
3534
        global $config;
3535

    
3536
        $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3537

    
3538
        if ($ifdesc) {
3539
                $iflist = get_configured_interface_with_descr(false, true);
3540
                return $iflist[$ifdesc];
3541
        }
3542

    
3543
        return $interface;
3544
}
3545

    
3546
/*
3547
 *  get_parent_interface($interface):
3548
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3549
 *				or virtual interface (i.e. vlan)
3550
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3551
 *			-- returns $interface passed in if $interface parent is not found
3552
 *			-- returns empty array if an invalid interface is passed
3553
 *	(Only handles ppps and vlans now.)
3554
 */
3555
function get_parent_interface($interface) {
3556
	global $config;
3557

    
3558
	$parents = array();
3559
	//Check that we got a valid interface passed
3560
	$realif = get_real_interface($interface);
3561
	if ($realif == NULL)
3562
		return $parents;
3563

    
3564
	// If we got a real interface, find it's friendly assigned name
3565
	$interface = convert_real_interface_to_friendly_interface_name($interface);
3566
		
3567
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3568
		$ifcfg = $config['interfaces'][$interface];
3569
		switch ($ifcfg['ipaddr']) {
3570
			case "ppp":
3571
			case "pppoe":
3572
			case "pptp":
3573
			case "l2tp":
3574
				if (empty($parents))
3575
					if (is_array($config['ppps']['ppp']))
3576
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3577
							if ($ppp_if == $ppp['if']) {
3578
								$ports = explode(',', $ppp['ports']);
3579
								foreach ($ports as $pid => $parent_if) 
3580
									$parents[$pid] = get_real_interface($parent_if);
3581
								break;
3582
							}
3583
						}
3584
				break;
3585
			case "dhcp":
3586
			case "static":
3587
			default:
3588
				// Handle _vlans
3589
				if (strstr($realif,"_vlan"))
3590
					if (is_array($config['vlans']['vlan'])) 
3591
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3592
							if ($ifcfg['if'] == $vlan['vlanif']){
3593
								$parents[0] = $vlan['if'];
3594
								break;
3595
							}
3596
				break;
3597
		}
3598
	}
3599
	
3600
	if (empty($parents))
3601
		$parents[0] = $realif;
3602
	
3603
	return $parents;
3604
}
3605

    
3606
function interface_is_wireless_clone($wlif) {
3607
	if(!stristr($wlif, "_wlan")) {
3608
		return false;
3609
	} else {
3610
		return true;
3611
	}
3612
}
3613

    
3614
function interface_get_wireless_base($wlif) {
3615
	if(!stristr($wlif, "_wlan")) {
3616
		return $wlif;
3617
	} else {
3618
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3619
	}
3620
}
3621

    
3622
function interface_get_wireless_clone($wlif) {
3623
	if(!stristr($wlif, "_wlan")) {
3624
		return $wlif . "_wlan0";
3625
	} else {
3626
		return $wlif;
3627
	}
3628
}
3629

    
3630
function get_real_interface($interface = "wan") {
3631
    global $config;
3632

    
3633
	$wanif = NULL;
3634

    
3635
	switch ($interface) {
3636
	case "l2tp":
3637
		$wanif = "l2tp";
3638
		break;
3639
	case "pptp":
3640
		$wanif = "pptp";
3641
		break;
3642
	case "pppoe":
3643
		$wanif = "pppoe";
3644
		break;
3645
	case "openvpn":
3646
		$wanif = "openvpn";
3647
		break;
3648
	case "ipsec":
3649
	case "enc0":
3650
		$wanif = "enc0";
3651
		break;
3652
	case "ppp":
3653
		$wanif = "ppp";
3654
		break;
3655
	default:
3656
		// If a real interface was alread passed simply
3657
		// pass the real interface back.  This encourages
3658
		// the usage of this function in more cases so that
3659
		// we can combine logic for more flexibility.
3660
		if(does_interface_exist($interface)) {
3661
			$wanif = $interface;
3662
			break;
3663
		}
3664

    
3665
		if (empty($config['interfaces'][$interface]))
3666
			break;
3667

    
3668
		$cfg = &$config['interfaces'][$interface];
3669

    
3670
		// Wireless cloned NIC support (FreeBSD 8+)
3671
		// interface name format: $parentnic_wlanparentnic#
3672
		// example: ath0_wlan0
3673
		if (is_interface_wireless($cfg['if'])) {
3674
			$wanif = interface_get_wireless_clone($cfg['if']);
3675
			break;
3676
		}
3677
		/*
3678
		if (empty($cfg['if'])) {
3679
			$wancfg = $cfg['if'];
3680
			break;
3681
		}
3682
		*/
3683

    
3684
		switch ($cfg['ipaddr']) {
3685
			case "pppoe": 
3686
			case "pptp": 
3687
			case "l2tp": 
3688
			case "ppp":
3689
				$wanif = $cfg['if'];
3690
				break;
3691
			default:
3692
				$wanif = $cfg['if'];
3693
				break;
3694
		}
3695
		break;
3696
	}
3697

    
3698
    return $wanif;
3699
}
3700

    
3701
/* Guess the physical interface by providing a IP address */
3702
function guess_interface_from_ip($ipaddress) {
3703
	if(! is_ipaddr($ipaddress)) {
3704
		return false;
3705
	}
3706
	if(is_ipaddrv4($ipaddress)) {
3707
		/* create a route table we can search */
3708
		exec("netstat -rnWf inet", $output, $ret);
3709
		foreach($output as $line) {
3710
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
3711
				$fields = preg_split("/[ ]+/", $line);
3712
				if(ip_in_subnet($ipaddress, $fields[0])) {
3713
					return $fields[6];
3714
				}
3715
			}
3716
		}
3717
	}
3718
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
3719
	if(is_ipaddrv6($ipaddress)) {
3720
		/* create a route table we can search */
3721
		exec("netstat -rnWf inet6", $output, $ret);
3722
		foreach($output as $line) {
3723
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
3724
				$fields = preg_split("/[ ]+/", $line);
3725
				if(ip_in_subnet($ipaddress, $fields[0])) {
3726
					return $fields[6];
3727
				}
3728
			}
3729
		}
3730
	}
3731
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
3732
	if(empty($ret)) {
3733
        	return false;
3734
	}
3735
	return $ret;
3736
}
3737

    
3738
/*
3739
 * find_ip_interface($ip): return the interface where an ip is defined
3740
 *   (or if $bits is specified, where an IP within the subnet is defined)
3741
 */
3742
function find_ip_interface($ip, $bits = null)
3743
{
3744
	/* if list */
3745
	$ifdescrs = get_configured_interface_list();
3746
		
3747
	foreach ($ifdescrs as $ifdescr => $ifname) {
3748
		if ($bits === null) {
3749
			if ($ip == get_interface_ip($ifname)) {
3750
				$int = get_real_interface($ifname);
3751
				return $int;
3752
			}
3753
		}
3754
		else {
3755
			if (ip_in_subnet(get_interface_ip($ifname), $ip . "/" . $bits)) {
3756
				$int = get_real_interface($ifname);
3757
				return $int;
3758
			}
3759
		}
3760
	}
3761
	return false;
3762
}
3763

    
3764
/*
3765
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
3766
 *   (or if $bits is specified, where an IP within the subnet is found)
3767
 */
3768
function find_virtual_ip_alias($ip, $bits = null) {
3769
	global $config;
3770
	if (!is_array($config['virtualip']['vip'])) {
3771
		return false;
3772
	}
3773
	foreach ($config['virtualip']['vip'] as $vip) {
3774
		if ($vip['mode'] === "ipalias") {
3775
			if ($bits === null) {
3776
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
3777
					return $vip;
3778
				}
3779
			}
3780
			else {
3781
				if (check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) {
3782
					return $vip;
3783
				}
3784
			}
3785
		}
3786
	}
3787
	return false;
3788
}
3789

    
3790
/*
3791
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
3792
 */
3793
function find_number_of_created_carp_interfaces() {
3794
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
3795
}
3796

    
3797
function get_all_carp_interfaces() {
3798
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
3799
	$ints = explode(" ", $ints);
3800
	return $ints;
3801
}
3802

    
3803
/*
3804
 * find_carp_interface($ip): return the carp interface where an ip is defined
3805
 */
3806
function find_carp_interface($ip) {
3807
	global $config;
3808
	if (is_array($config['virtualip']['vip'])) {
3809
		foreach ($config['virtualip']['vip'] as $vip) {
3810
			if ($vip['mode'] == "carp") {
3811
				if(is_ipaddrv4($ip)) {
3812
					$carp_ip = get_interface_ip($vip['interface']);
3813
				}
3814
				if(is_ipaddrv6($ip)) {
3815
					$carp_ip = get_interface_ipv6($vip['interface']);
3816
				}
3817
				exec("/sbin/ifconfig", $output, $return);
3818
				foreach($output as $line) {
3819
					$elements = preg_split("/[ ]+/i", $line);
3820
					if(strstr($elements[0], "vip"))
3821
						$curif = str_replace(":", "", $elements[0]);
3822
					if(stristr($line, $ip)) {
3823
						$if = $curif;
3824
						continue;
3825
					}
3826
				}
3827

    
3828
				if ($if)
3829
					return $if;
3830
			}
3831
		}
3832
	}
3833
}
3834

    
3835
function link_carp_interface_to_parent($interface) {
3836
	global $config;
3837

    
3838
	if ($interface == "")
3839
		return;
3840

    
3841
	$carp_ip = get_interface_ip($interface);
3842
	$carp_ipv6 = get_interface_ipv6($interface);
3843

    
3844
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
3845
		return;
3846

    
3847
	/* if list */
3848
	$ifdescrs = get_configured_interface_list();
3849
	foreach ($ifdescrs as $ifdescr => $ifname) {
3850
		/* check IPv4 */
3851
		if(is_ipaddrv4($carp_ip)) {
3852
			$interfaceip = get_interface_ip($ifname);
3853
			$subnet_bits = get_interface_subnet($ifname);
3854
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3855
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3856
				return $ifname;
3857
		}
3858
		/* Check IPv6 */
3859
		if(is_ipaddrv6($carp_ipv6)) {
3860
			$interfaceipv6 = get_interface_ipv6($ifname);
3861
			$prefixlen = get_interface_subnetv6($ifname);
3862
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
3863
				return $ifname;
3864
		}
3865
	}
3866
	return "";
3867
}
3868

    
3869

    
3870
/****f* interfaces/link_ip_to_carp_interface
3871
 * NAME
3872
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3873
 * INPUTS
3874
 *   $ip
3875
 * RESULT
3876
 *   $carp_ints
3877
 ******/
3878
function link_ip_to_carp_interface($ip) {
3879
        global $config;
3880

    
3881
        if (!is_ipaddr($ip))
3882
                return;
3883

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

    
3902
        return $carp_ints;
3903
}
3904

    
3905
function link_interface_to_vlans($int, $action = "") {
3906
	global $config;
3907

    
3908
	if (empty($int))
3909
		return;
3910

    
3911
	if (is_array($config['vlans']['vlan'])) {
3912
                foreach ($config['vlans']['vlan'] as $vlan) {
3913
			if ($int == $vlan['if']) {
3914
				if ($action == "update") {
3915
					interfaces_bring_up($int);
3916
				} else if ($action == "")
3917
					return $vlan;
3918
			}
3919
		}
3920
	}
3921
}
3922

    
3923
function link_interface_to_vips($int, $action = "") {
3924
        global $config;
3925

    
3926
        if (is_array($config['virtualip']['vip'])) {
3927
		foreach ($config['virtualip']['vip'] as $vip) {
3928
			if ($int == $vip['interface']) {
3929
				if ($action == "update")
3930
					interfaces_vips_configure($int);
3931
				else
3932
					return $vip;
3933
			}
3934
		}
3935
	}
3936
}
3937

    
3938
/****f* interfaces/link_interface_to_bridge
3939
 * NAME
3940
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3941
 * INPUTS
3942
 *   $ip
3943
 * RESULT
3944
 *   bridge[0-99]
3945
 ******/
3946
function link_interface_to_bridge($int) {
3947
        global $config;
3948

    
3949
        if (is_array($config['bridges']['bridged'])) {
3950
                foreach ($config['bridges']['bridged'] as $bridge) {
3951
			if (in_array($int, explode(',', $bridge['members'])))
3952
                                return "{$bridge['bridgeif']}";
3953
		}
3954
	}
3955
}
3956

    
3957
function link_interface_to_group($int) {
3958
        global $config;
3959

    
3960
	$result = array();
3961

    
3962
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3963
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3964
			if (in_array($int, explode(" ", $group['members'])))
3965
				$result[$group['ifname']] = $int;
3966
		}
3967
	}
3968

    
3969
	return $result;
3970
}
3971

    
3972
function link_interface_to_gre($interface) {
3973
        global $config;
3974

    
3975
	$result = array();
3976

    
3977
        if (is_array($config['gres']['gre'])) {
3978
                foreach ($config['gres']['gre'] as $gre)
3979
                        if($gre['if'] == $interface)
3980
				$result[] = $gre;
3981
	}
3982

    
3983
	return $result;
3984
}
3985

    
3986
function link_interface_to_gif($interface) {
3987
        global $config;
3988

    
3989
	$result = array();
3990

    
3991
        if (is_array($config['gifs']['gif'])) {
3992
                foreach ($config['gifs']['gif'] as $gif)
3993
                        if($gif['if'] == $interface)
3994
                                $result[] = $gif;
3995
	}
3996

    
3997
	return $result;
3998
}
3999

    
4000
/*
4001
 * find_interface_ip($interface): return the interface ip (first found)
4002
 */
4003
function find_interface_ip($interface, $flush = false)
4004
{
4005
	global $interface_ip_arr_cache;
4006
	global $interface_sn_arr_cache;
4007

    
4008
	$interface = str_replace("\n", "", $interface);
4009
	
4010
	if (!does_interface_exist($interface))
4011
		return;
4012

    
4013
	/* Setup IP cache */
4014
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4015
		$ifinfo = pfSense_get_interface_addresses($interface);
4016
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4017
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4018
	}
4019

    
4020
	return $interface_ip_arr_cache[$interface];
4021
}
4022

    
4023
/*
4024
 * find_interface_ipv6($interface): return the interface ip (first found)
4025
 */
4026
function find_interface_ipv6($interface, $flush = false)
4027
{
4028
	global $interface_ipv6_arr_cache;
4029
	global $interface_snv6_arr_cache;
4030
	global $config;
4031
	
4032
	$interface = trim($interface);
4033
	$interface = get_real_interface($interface);
4034
	
4035
	if (!does_interface_exist($interface))
4036
		return;
4037

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

    
4061
	return $interface_ipv6_arr_cache[$interface];
4062
}
4063

    
4064
/*
4065
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4066
 */
4067
function find_interface_ipv6_ll($interface, $flush = false)
4068
{
4069
	global $interface_llv6_arr_cache;
4070
	global $config;
4071
	
4072
	$interface = str_replace("\n", "", $interface);
4073
	
4074
	if (!does_interface_exist($interface))
4075
		return;
4076

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

    
4096
function find_interface_subnet($interface, $flush = false)
4097
{
4098
	global $interface_sn_arr_cache;
4099
	global $interface_ip_arr_cache;
4100

    
4101
	$interface = str_replace("\n", "", $interface);
4102
	if (does_interface_exist($interface) == false)
4103
		return;
4104

    
4105
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4106
		$ifinfo = pfSense_get_interface_addresses($interface);
4107
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4108
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4109
        }
4110

    
4111
	return $interface_sn_arr_cache[$interface];
4112
}
4113

    
4114
function find_interface_subnetv6($interface, $flush = false)
4115
{
4116
	global $interface_snv6_arr_cache;
4117
	global $interface_ipv6_arr_cache;
4118

    
4119
	$interface = str_replace("\n", "", $interface);
4120
	if (does_interface_exist($interface) == false)
4121
		return;
4122

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

    
4145
	return $interface_snv6_arr_cache[$interface];
4146
}
4147

    
4148
function ip_in_interface_alias_subnet($interface, $ipalias) {
4149
	global $config;
4150

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

    
4166
	return false;
4167
}
4168

    
4169
function get_interface_ip($interface = "wan")
4170
{
4171
	$realif = get_failover_interface($interface);
4172
	if (!$realif) {
4173
		if (preg_match("/^carp/i", $interface))
4174
			$realif = $interface;
4175
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4176
			$realif = $interface;
4177
		else
4178
			return null;
4179
	}
4180

    
4181
	$curip = find_interface_ip($realif);
4182
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4183
		return $curip;
4184
	else
4185
		return null;
4186
}
4187

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

    
4207
	$curip = find_interface_ipv6($realif);
4208
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4209
		return $curip;
4210
	else
4211
		return null;
4212
}
4213

    
4214
function get_interface_linklocal($interface = "wan")
4215
{
4216
	$realif = get_failover_interface($interface);
4217
	if (!$realif) {
4218
		if (preg_match("/^carp/i", $interface))
4219
			$realif = $interface;
4220
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4221
			$realif = $interface;
4222
		else
4223
			return null;
4224
	}
4225

    
4226
	$curip = find_interface_ipv6_ll($realif);
4227
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4228
		return $curip;
4229
	else
4230
		return null;
4231
}
4232

    
4233
function get_interface_subnet($interface = "wan")
4234
{
4235
	$realif = get_real_interface($interface);
4236
	if (!$realif) {
4237
                if (preg_match("/^carp/i", $interface))
4238
                        $realif = $interface;
4239
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4240
                        $realif = $interface;
4241
                else
4242
                        return null;
4243
        }
4244

    
4245
	$cursn = find_interface_subnet($realif);
4246
	if (!empty($cursn))
4247
		return $cursn;
4248

    
4249
	return null;
4250
}
4251

    
4252
function get_interface_subnetv6($interface = "wan")
4253
{
4254
	$realif = get_real_interface($interface);
4255
	if (!$realif) {
4256
                if (preg_match("/^carp/i", $interface))
4257
                        $realif = $interface;
4258
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4259
                        $realif = $interface;
4260
                else
4261
                        return null;
4262
        }
4263

    
4264
	$cursn = find_interface_subnetv6($realif);
4265
	if (!empty($cursn))
4266
		return $cursn;
4267

    
4268
	return null;
4269
}
4270

    
4271
/* return outside interfaces with a gateway */
4272
function get_interfaces_with_gateway() {
4273
	global $config;
4274

    
4275
	$ints = array();
4276

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

    
4298
/* return true if interface has a gateway */
4299
function interface_has_gateway($friendly) {
4300
	global $config;
4301

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

    
4321
	return false;
4322
}
4323

    
4324
/* return true if interface has a gateway */
4325
function interface_has_gatewayv6($friendly) {
4326
	global $config;
4327

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

    
4350
	return false;
4351
}
4352

    
4353
/****f* interfaces/is_altq_capable
4354
 * NAME
4355
 *   is_altq_capable - Test if interface is capable of using ALTQ
4356
 * INPUTS
4357
 *   $int            - string containing interface name
4358
 * RESULT
4359
 *   boolean         - true or false
4360
 ******/
4361

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

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

    
4377
        if (in_array($int_family[0], $capable))
4378
                return true;
4379
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4380
		return true;
4381
	else if (stristr($int, "vlan")) /* VLANs are name $parent_$vlan now */
4382
		return true;
4383
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4384
		return true;
4385
        else
4386
                return false;
4387
}
4388

    
4389
/****f* interfaces/is_interface_wireless
4390
 * NAME
4391
 *   is_interface_wireless - Returns if an interface is wireless
4392
 * RESULT
4393
 *   $tmp       - Returns if an interface is wireless
4394
 ******/
4395
function is_interface_wireless($interface) {
4396
        global $config, $g;
4397

    
4398
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
4399
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
4400
                if (preg_match($g['wireless_regex'], $interface)) {
4401
                        if (isset($config['interfaces'][$friendly]))
4402
                                $config['interfaces'][$friendly]['wireless'] = array();
4403
                        return true;
4404
                }
4405
                return false;
4406
        } else
4407
                return true;
4408
}
4409

    
4410
function get_wireless_modes($interface) {
4411
	/* return wireless modes and channels */
4412
	$wireless_modes = array();
4413

    
4414
	$cloned_interface = get_real_interface($interface);
4415

    
4416
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4417
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4418
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4419
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4420

    
4421
		$interface_channels = "";
4422
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4423
		$interface_channel_count = count($interface_channels);
4424

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

    
4455
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4456
function get_wireless_channel_info($interface) {
4457
	$wireless_channels = array();
4458

    
4459
	$cloned_interface = get_real_interface($interface);
4460

    
4461
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4462
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4463
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4464
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4465

    
4466
		$interface_channels = "";
4467
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4468

    
4469
		foreach ($interface_channels as $channel_line) {
4470
			$channel_line = explode(",", $channel_line);
4471
			if(!isset($wireless_channels[$channel_line[0]]))
4472
				$wireless_channels[$channel_line[0]] = $channel_line;
4473
		}
4474
	}
4475
	return($wireless_channels);
4476
}
4477

    
4478
/****f* interfaces/get_interface_mtu
4479
 * NAME
4480
 *   get_interface_mtu - Return the mtu of an interface
4481
 * RESULT
4482
 *   $tmp       - Returns the mtu of an interface
4483
 ******/
4484
function get_interface_mtu($interface) {
4485
        $mtu = pfSense_get_interface_addresses($interface);
4486
        return $mtu['mtu'];
4487
}
4488

    
4489
function get_interface_mac($interface) {
4490

    
4491
	$macinfo = pfSense_get_interface_addresses($interface);
4492
	return $macinfo["macaddr"];
4493
}
4494

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

    
4510
/****f* interfaces/is_jumbo_capable
4511
 * NAME
4512
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4513
 * INPUTS
4514
 *   $int             - string containing interface name
4515
 * RESULT
4516
 *   boolean          - true or false
4517
 ******/
4518
function is_jumbo_capable($iface) {
4519

    
4520

    
4521
	$iface = trim($iface);
4522
	$capable = pfSense_get_interface_addresses($iface);
4523
	if (isset($capable['caps']['vlanmtu']))
4524
                return true;
4525

    
4526

    
4527

    
4528

    
4529

    
4530
	return false;
4531
}
4532

    
4533
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4534
	global $g;
4535

    
4536
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4537

    
4538
	if(!empty($iface) && !empty($pppif)){
4539
		$cron_cmd = <<<EOD
4540
#!/bin/sh
4541
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4542
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4543

    
4544
EOD;
4545

    
4546
		@file_put_contents($cron_file, $cron_cmd);
4547
		chmod($cron_file, 0755);
4548
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4549
	} else
4550
		unlink_if_exists($cron_file);
4551
}
4552

    
4553
function get_interface_default_mtu($type = "ethernet") {
4554
	switch ($type) {
4555
	case "gre":
4556
		return 1476;
4557
		break;
4558
	case "gif":
4559
		return 1280;
4560
		break;
4561
	case "tun":
4562
	case "vlan":
4563
	case "tap":
4564
	case "ethernet":
4565
	default:
4566
		return 1500;
4567
		break;
4568
	}
4569

    
4570
	/* Never reached */
4571
	return 1500;
4572
}
4573

    
4574
function get_vip_descr($ipaddress) {
4575
	global $config;
4576

    
4577
	foreach ($config['virtualip']['vip'] as $vip) {
4578
		if ($vip['subnet'] == $ipaddress) {
4579
			return ($vip['descr']);
4580
		}
4581
	}
4582
	return "";
4583
}
4584

    
4585
function interfaces_staticarp_configure($if) {
4586
	global $config, $g;
4587
	if(isset($config['system']['developerspew'])) {
4588
		$mt = microtime();
4589
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4590
	}
4591

    
4592
	$ifcfg = $config['interfaces'][$if];
4593

    
4594
	if (empty($if) || empty($ifcfg['if']))
4595
		return 0;
4596

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

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

    
4606
			}
4607

    
4608
		}
4609
	} else {
4610
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4611
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4612
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4613
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4614
				if (isset($arpent['arp_table_static_entry'])) {
4615
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4616
				}
4617
			}
4618
		}
4619
	}
4620

    
4621
	return 0;
4622
}
4623

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

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

    
4648
?>
(26-26/68)