Project

General

Profile

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

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

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

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

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

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

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

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

    
43
*/
44

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

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

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

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

    
70
        return $interface_arr_cache;
71
}
72

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

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

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

    
100

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

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

    
126
	return false;
127
}
128

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
	interfaces_bring_up($vlanif);
270

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

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

    
277
	return $vlanif;
278
}
279

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

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

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

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

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

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

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

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

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

    
347
        return $vlanif;
348
}
349

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

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

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

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

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

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

    
390
        return $vlanif;
391
}
392

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

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

    
413
}
414

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

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

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

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

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

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

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

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

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

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

    
502
	$checklist = get_configured_interface_list();
503

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

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

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

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

    
626
	return $bridgeif;
627
}
628

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
727
	$checklist = get_interface_list();
728

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

    
741
	interfaces_bring_up($laggif);
742

    
743
	return $laggif;
744
}
745

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

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

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

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

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

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

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

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

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

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

    
809
	return $greif;
810
}
811

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

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

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

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

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

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

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

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

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

    
889

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

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

    
902
	return $gifif;
903
}
904

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

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

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

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

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

    
920
	interfaces_qinq_configure();
921

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

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

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

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

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

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

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

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

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

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

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

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

    
987
		interface_configure($if, $reload);
988

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

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

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

    
1002
		interface_configure($if, $reload);
1003

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

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

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

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

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

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

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

    
1028
	return 0;
1029
}
1030

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

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

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

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

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

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

    
1067
	$realif = get_real_interface($interface);
1068

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

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

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

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

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

    
1184
	return;
1185
}
1186

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

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

    
1195
	return false;
1196
}
1197

    
1198
function interfaces_ptpid_next() {
1199

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

    
1204
	return $ptpid;
1205
}
1206

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1506
EOD;
1507

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

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

    
1521
EOD;
1522

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

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

    
1533
EOD;
1534

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

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

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

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

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

    
1561
EOD;
1562

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

    
1567
EOD;
1568

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

    
1573
EOD;
1574

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

    
1580
EOD;
1581

    
1582

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

    
1587
EOD;
1588

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

    
1594
EOD;
1595

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

    
1600
EOD;
1601

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

    
1606
EOD;
1607

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

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

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

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

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

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

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

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

    
1664
EOD;
1665

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

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

    
1677

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

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

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

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

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

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

    
1752
	return 1;
1753
}
1754

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

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

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

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

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

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

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

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

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

    
1820
	sleep(1);
1821

    
1822
	/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
1823
	 * for existing sessions.
1824
	 */
1825
	if ($config['hasync']['pfsyncenabled'] === "on"){
1826
		echo "waiting for pfsync...";
1827
		$i = 0;
1828
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1829
			$i++;
1830
			sleep(1);
1831
		}
1832
		echo "pfsync done in $i seconds.\n";
1833
		echo "Configuring CARP settings finalize...";
1834
	}
1835

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2073
	interfaces_bring_up($vipif);
2074

    
2075
	return $vipif;
2076
}
2077

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2436
EOD;
2437

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

    
2444
EOD;
2445

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

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

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

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

    
2473
			}
2474
			break;
2475
	}
2476

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2622
	return 0;
2623

    
2624
}
2625

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

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

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

    
2640
	return intval($pid);
2641
}
2642

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

    
2649
	return intval($pid);
2650
}
2651

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

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

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

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

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

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

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

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

    
2705
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2706
			/*   this is not a valid mac address.  generate a
2707
			 *   temporary mac address so the machine can get online.
2708
			 */
2709
			echo gettext("Generating new MAC address.");
2710
			$random_mac = generate_random_mac_address();
2711
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2712
				" link " . escapeshellarg($random_mac));
2713
			$wancfg['spoofmac'] = $random_mac;
2714
			write_config();
2715
			file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
2716
		}
2717
	}
2718

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2880
		if ($reloadall == true) {
2881

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

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

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

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

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

    
2899
	return 0;
2900
}
2901

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

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

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

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

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

    
2943

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3301
	$wanif = get_real_interface($interface);
3302

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

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

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

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

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

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

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

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

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

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

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

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

    
3388
EOD;
3389

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

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

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

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

    
3413
	return 0;
3414
}
3415

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

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

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

    
3425
	return;
3426
}
3427

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

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

    
3440
	return;
3441
}
3442

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

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

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

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

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

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

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

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

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

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

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

    
3548
        return $ifdesc;
3549
}
3550

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

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

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

    
3561
        return $interface;
3562
}
3563

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

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

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

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

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

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

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

    
3651
	$wanif = NULL;
3652

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

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

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

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

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

    
3716
    return $wanif;
3717
}
3718

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

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

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

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

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

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

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

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

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

    
3859
	$carp_ip = get_interface_ip($interface);
3860
	$carp_ipv6 = get_interface_ipv6($interface);
3861

    
3862
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
3863
		return;
3864

    
3865
	/* if list */
3866
	$ifdescrs = get_configured_interface_list();
3867
	foreach ($ifdescrs as $ifdescr => $ifname) {
3868
		/* check IPv4 */
3869
		if(is_ipaddrv4($carp_ip)) {
3870
			$interfaceip = get_interface_ip($ifname);
3871
			$subnet_bits = get_interface_subnet($ifname);
3872
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3873
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3874
				return $ifname;
3875
		}
3876
		/* Check IPv6 */
3877
		if(is_ipaddrv6($carp_ipv6)) {
3878
			$interfaceipv6 = get_interface_ipv6($ifname);
3879
			$prefixlen = get_interface_subnetv6($ifname);
3880
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
3881
				return $ifname;
3882
		}
3883
	}
3884
	return "";
3885
}
3886

    
3887

    
3888
/****f* interfaces/link_ip_to_carp_interface
3889
 * NAME
3890
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3891
 * INPUTS
3892
 *   $ip
3893
 * RESULT
3894
 *   $carp_ints
3895
 ******/
3896
function link_ip_to_carp_interface($ip) {
3897
        global $config;
3898

    
3899
        if (!is_ipaddr($ip))
3900
                return;
3901

    
3902
        $carp_ints = "";
3903
        if (is_array($config['virtualip']['vip'])) {
3904
		$first = 0;
3905
		$carp_int = array();
3906
                foreach ($config['virtualip']['vip'] as $vip) {
3907
                        if ($vip['mode'] == "carp") {
3908
                                $carp_ip = $vip['subnet'];
3909
                                $carp_sn = $vip['subnet_bits'];
3910
                                $carp_nw = gen_subnet($carp_ip, $carp_sn);
3911
                                if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
3912
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
3913
				}
3914
                        }
3915
                }
3916
		if (!empty($carp_int))
3917
			$carp_ints = implode(" ", array_unique($carp_int));
3918
        }
3919

    
3920
        return $carp_ints;
3921
}
3922

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

    
3926
	if (empty($int))
3927
		return;
3928

    
3929
	if (is_array($config['vlans']['vlan'])) {
3930
                foreach ($config['vlans']['vlan'] as $vlan) {
3931
			if ($int == $vlan['if']) {
3932
				if ($action == "update") {
3933
					interfaces_bring_up($int);
3934
				} else if ($action == "")
3935
					return $vlan;
3936
			}
3937
		}
3938
	}
3939
}
3940

    
3941
function link_interface_to_vips($int, $action = "") {
3942
        global $config;
3943

    
3944
        if (is_array($config['virtualip']['vip'])) {
3945
		foreach ($config['virtualip']['vip'] as $vip) {
3946
			if ($int == $vip['interface']) {
3947
				if ($action == "update")
3948
					interfaces_vips_configure($int);
3949
				else
3950
					return $vip;
3951
			}
3952
		}
3953
	}
3954
}
3955

    
3956
/****f* interfaces/link_interface_to_bridge
3957
 * NAME
3958
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3959
 * INPUTS
3960
 *   $ip
3961
 * RESULT
3962
 *   bridge[0-99]
3963
 ******/
3964
function link_interface_to_bridge($int) {
3965
        global $config;
3966

    
3967
        if (is_array($config['bridges']['bridged'])) {
3968
                foreach ($config['bridges']['bridged'] as $bridge) {
3969
			if (in_array($int, explode(',', $bridge['members'])))
3970
                                return "{$bridge['bridgeif']}";
3971
		}
3972
	}
3973
}
3974

    
3975
function link_interface_to_group($int) {
3976
        global $config;
3977

    
3978
	$result = array();
3979

    
3980
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3981
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3982
			if (in_array($int, explode(" ", $group['members'])))
3983
				$result[$group['ifname']] = $int;
3984
		}
3985
	}
3986

    
3987
	return $result;
3988
}
3989

    
3990
function link_interface_to_gre($interface) {
3991
        global $config;
3992

    
3993
	$result = array();
3994

    
3995
        if (is_array($config['gres']['gre'])) {
3996
                foreach ($config['gres']['gre'] as $gre)
3997
                        if($gre['if'] == $interface)
3998
				$result[] = $gre;
3999
	}
4000

    
4001
	return $result;
4002
}
4003

    
4004
function link_interface_to_gif($interface) {
4005
        global $config;
4006

    
4007
	$result = array();
4008

    
4009
        if (is_array($config['gifs']['gif'])) {
4010
                foreach ($config['gifs']['gif'] as $gif)
4011
                        if($gif['if'] == $interface)
4012
                                $result[] = $gif;
4013
	}
4014

    
4015
	return $result;
4016
}
4017

    
4018
/*
4019
 * find_interface_ip($interface): return the interface ip (first found)
4020
 */
4021
function find_interface_ip($interface, $flush = false)
4022
{
4023
	global $interface_ip_arr_cache;
4024
	global $interface_sn_arr_cache;
4025

    
4026
	$interface = str_replace("\n", "", $interface);
4027
	
4028
	if (!does_interface_exist($interface))
4029
		return;
4030

    
4031
	/* Setup IP cache */
4032
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4033
		$ifinfo = pfSense_get_interface_addresses($interface);
4034
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4035
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4036
	}
4037

    
4038
	return $interface_ip_arr_cache[$interface];
4039
}
4040

    
4041
/*
4042
 * find_interface_ipv6($interface): return the interface ip (first found)
4043
 */
4044
function find_interface_ipv6($interface, $flush = false)
4045
{
4046
	global $interface_ipv6_arr_cache;
4047
	global $interface_snv6_arr_cache;
4048
	global $config;
4049
	
4050
	$interface = trim($interface);
4051
	$interface = get_real_interface($interface);
4052
	
4053
	if (!does_interface_exist($interface))
4054
		return;
4055

    
4056
	/* Setup IP cache */
4057
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4058
		$ifinfo = pfSense_get_interface_addresses($interface);
4059
		// FIXME: Add IPv6 support to the pfSense module
4060
		exec("/sbin/ifconfig {$interface} inet6", $output);
4061
		foreach($output as $line) {
4062
			if(preg_match("/inet6/", $line)) {
4063
				$parts = explode(" ", $line);
4064
				if(! preg_match("/fe80::/", $parts[1])) {
4065
					$ifinfo['ipaddrv6'] = $parts[1];
4066
					if($parts[2] == "-->") {
4067
						$parts[5] = "126";
4068
						$ifinfo['subnetbitsv6'] = $parts[5];
4069
					} else {
4070
						$ifinfo['subnetbitsv6'] = $parts[3];
4071
					}
4072
				}
4073
			}
4074
		}
4075
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4076
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4077
	}
4078

    
4079
	return $interface_ipv6_arr_cache[$interface];
4080
}
4081

    
4082
/*
4083
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4084
 */
4085
function find_interface_ipv6_ll($interface, $flush = false)
4086
{
4087
	global $interface_llv6_arr_cache;
4088
	global $config;
4089
	
4090
	$interface = str_replace("\n", "", $interface);
4091
	
4092
	if (!does_interface_exist($interface))
4093
		return;
4094

    
4095
	/* Setup IP cache */
4096
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4097
		$ifinfo = pfSense_get_interface_addresses($interface);
4098
		// FIXME: Add IPv6 support to the pfSense module
4099
		exec("/sbin/ifconfig {$interface} inet6", $output);
4100
		foreach($output as $line) {
4101
			if(preg_match("/inet6/", $line)) {
4102
				$parts = explode(" ", $line);
4103
				if(preg_match("/fe80::/", $parts[1])) {
4104
					$partsaddress = explode("%", $parts[1]);
4105
					$ifinfo['linklocal'] = $partsaddress[0];
4106
				}
4107
			}
4108
		}
4109
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4110
	}
4111
	return $interface_llv6_arr_cache[$interface];
4112
}
4113

    
4114
function find_interface_subnet($interface, $flush = false)
4115
{
4116
	global $interface_sn_arr_cache;
4117
	global $interface_ip_arr_cache;
4118

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

    
4123
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4124
		$ifinfo = pfSense_get_interface_addresses($interface);
4125
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4126
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4127
        }
4128

    
4129
	return $interface_sn_arr_cache[$interface];
4130
}
4131

    
4132
function find_interface_subnetv6($interface, $flush = false)
4133
{
4134
	global $interface_snv6_arr_cache;
4135
	global $interface_ipv6_arr_cache;
4136

    
4137
	$interface = str_replace("\n", "", $interface);
4138
	if (does_interface_exist($interface) == false)
4139
		return;
4140

    
4141
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4142
		$ifinfo = pfSense_get_interface_addresses($interface);
4143
		// FIXME: Add IPv6 support to the pfSense module
4144
		exec("/sbin/ifconfig {$interface} inet6", $output);
4145
		foreach($output as $line) {
4146
			if(preg_match("/inet6/", $line)) {
4147
				$parts = explode(" ", $line);
4148
				if(! preg_match("/fe80::/", $parts[1])) {
4149
					$ifinfo['ipaddrv6'] = $parts[1];
4150
					if($parts[2] == "-->") {
4151
						$parts[5] = "126";
4152
						$ifinfo['subnetbitsv6'] = $parts[5];
4153
					} else {
4154
						$ifinfo['subnetbitsv6'] = $parts[3];
4155
					}
4156
				}
4157
			}
4158
		}
4159
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4160
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4161
        }
4162

    
4163
	return $interface_snv6_arr_cache[$interface];
4164
}
4165

    
4166
function ip_in_interface_alias_subnet($interface, $ipalias) {
4167
	global $config;
4168

    
4169
	if (empty($interface) || !is_ipaddr($ipalias))
4170
		return false;
4171
	if (is_array($config['virtualip']['vip'])) {
4172
                foreach ($config['virtualip']['vip'] as $vip) {
4173
                        switch ($vip['mode']) {
4174
                        case "ipalias":
4175
                                if ($vip['interface'] <> $interface)
4176
                                        break;
4177
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
4178
					return true;
4179
                                break;
4180
                        }
4181
                }
4182
	}
4183

    
4184
	return false;
4185
}
4186

    
4187
function get_interface_ip($interface = "wan")
4188
{
4189
	$realif = get_failover_interface($interface);
4190
	if (!$realif) {
4191
		if (preg_match("/^carp/i", $interface))
4192
			$realif = $interface;
4193
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4194
			$realif = $interface;
4195
		else
4196
			return null;
4197
	}
4198

    
4199
	$curip = find_interface_ip($realif);
4200
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4201
		return $curip;
4202
	else
4203
		return null;
4204
}
4205

    
4206
function get_interface_ipv6($interface = "wan")
4207
{
4208
	global $config;
4209
	$realif = get_failover_interface($interface);
4210
	switch($config['interfaces'][$interface]['ipaddrv6']) {
4211
		case "6rd":
4212
		case "6to4":
4213
			$realif = "stf0";
4214
			break;
4215
	}
4216
	if (!$realif) {
4217
		if (preg_match("/^carp/i", $interface))
4218
			$realif = $interface;
4219
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4220
			$realif = $interface;
4221
		else
4222
			return null;
4223
	}
4224

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

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

    
4244
	$curip = find_interface_ipv6_ll($realif);
4245
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4246
		return $curip;
4247
	else
4248
		return null;
4249
}
4250

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

    
4263
	$cursn = find_interface_subnet($realif);
4264
	if (!empty($cursn))
4265
		return $cursn;
4266

    
4267
	return null;
4268
}
4269

    
4270
function get_interface_subnetv6($interface = "wan")
4271
{
4272
	$realif = get_real_interface($interface);
4273
	if (!$realif) {
4274
                if (preg_match("/^carp/i", $interface))
4275
                        $realif = $interface;
4276
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4277
                        $realif = $interface;
4278
                else
4279
                        return null;
4280
        }
4281

    
4282
	$cursn = find_interface_subnetv6($realif);
4283
	if (!empty($cursn))
4284
		return $cursn;
4285

    
4286
	return null;
4287
}
4288

    
4289
/* return outside interfaces with a gateway */
4290
function get_interfaces_with_gateway() {
4291
	global $config;
4292

    
4293
	$ints = array();
4294

    
4295
	/* loop interfaces, check config for outbound */
4296
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4297
		switch ($ifname['ipaddr']) {
4298
			case "dhcp":
4299
			case "ppp";
4300
			case "pppoe":
4301
			case "pptp":
4302
			case "l2tp":
4303
			case "ppp";
4304
				$ints[$ifdescr] = $ifdescr;
4305
			break;
4306
			default:
4307
				if (substr($ifname['if'], 0, 5) ==  "ovpnc" ||
4308
				    !empty($ifname['gateway']))
4309
					$ints[$ifdescr] = $ifdescr;
4310
			break;
4311
		}
4312
	}
4313
	return $ints;
4314
}
4315

    
4316
/* return true if interface has a gateway */
4317
function interface_has_gateway($friendly) {
4318
	global $config;
4319

    
4320
	if (!empty($config['interfaces'][$friendly])) {
4321
		$ifname = &$config['interfaces'][$friendly];
4322
		switch ($ifname['ipaddr']) {
4323
			case "dhcp":
4324
			case "pppoe":
4325
			case "pptp":
4326
			case "l2tp":
4327
			case "ppp";
4328
				return true;
4329
			break;
4330
			default:
4331
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
4332
					return true;
4333
				if (!empty($ifname['gateway']))
4334
					return true;
4335
			break;
4336
		}
4337
	}
4338

    
4339
	return false;
4340
}
4341

    
4342
/* return true if interface has a gateway */
4343
function interface_has_gatewayv6($friendly) {
4344
	global $config;
4345

    
4346
	if (!empty($config['interfaces'][$friendly])) {
4347
		$ifname = &$config['interfaces'][$friendly];
4348
		switch ($ifname['ipaddrv6']) {
4349
			case "slaac":
4350
			case "dhcp6":
4351
				return true;
4352
				break;
4353
			case "6to4":
4354
				return true;
4355
				break;
4356
			case "6rd":
4357
				return true;
4358
				break;
4359
			default:
4360
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
4361
					return true;
4362
				if (!empty($ifname['gatewayv6']))
4363
					return true;
4364
				break;
4365
		}
4366
	}
4367

    
4368
	return false;
4369
}
4370

    
4371
/****f* interfaces/is_altq_capable
4372
 * NAME
4373
 *   is_altq_capable - Test if interface is capable of using ALTQ
4374
 * INPUTS
4375
 *   $int            - string containing interface name
4376
 * RESULT
4377
 *   boolean         - true or false
4378
 ******/
4379

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

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

    
4395
        if (in_array($int_family[0], $capable))
4396
                return true;
4397
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4398
		return true;
4399
	else if (stristr($int, "vlan")) /* VLANs are name $parent_$vlan now */
4400
		return true;
4401
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4402
		return true;
4403
        else
4404
                return false;
4405
}
4406

    
4407
/****f* interfaces/is_interface_wireless
4408
 * NAME
4409
 *   is_interface_wireless - Returns if an interface is wireless
4410
 * RESULT
4411
 *   $tmp       - Returns if an interface is wireless
4412
 ******/
4413
function is_interface_wireless($interface) {
4414
        global $config, $g;
4415

    
4416
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
4417
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
4418
                if (preg_match($g['wireless_regex'], $interface)) {
4419
                        if (isset($config['interfaces'][$friendly]))
4420
                                $config['interfaces'][$friendly]['wireless'] = array();
4421
                        return true;
4422
                }
4423
                return false;
4424
        } else
4425
                return true;
4426
}
4427

    
4428
function get_wireless_modes($interface) {
4429
	/* return wireless modes and channels */
4430
	$wireless_modes = array();
4431

    
4432
	$cloned_interface = get_real_interface($interface);
4433

    
4434
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4435
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4436
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4437
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4438

    
4439
		$interface_channels = "";
4440
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4441
		$interface_channel_count = count($interface_channels);
4442

    
4443
		$c = 0;
4444
		while ($c < $interface_channel_count)
4445
		{
4446
			$channel_line = explode(",", $interface_channels["$c"]);
4447
			$wireless_mode = trim($channel_line[0]);
4448
			$wireless_channel = trim($channel_line[1]);
4449
			if(trim($wireless_mode) != "") {
4450
				/* if we only have 11g also set 11b channels */
4451
				if($wireless_mode == "11g") {
4452
					if(!isset($wireless_modes["11b"]))
4453
						$wireless_modes["11b"] = array();
4454
				} else if($wireless_mode == "11g ht") {
4455
					if(!isset($wireless_modes["11b"]))
4456
						$wireless_modes["11b"] = array();
4457
					if(!isset($wireless_modes["11g"]))
4458
						$wireless_modes["11g"] = array();
4459
					$wireless_mode = "11ng";
4460
				} else if($wireless_mode == "11a ht") {
4461
					if(!isset($wireless_modes["11a"]))
4462
						$wireless_modes["11a"] = array();
4463
					$wireless_mode = "11na";
4464
				}
4465
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4466
			}
4467
			$c++;
4468
		}
4469
	}
4470
	return($wireless_modes);
4471
}
4472

    
4473
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4474
function get_wireless_channel_info($interface) {
4475
	$wireless_channels = array();
4476

    
4477
	$cloned_interface = get_real_interface($interface);
4478

    
4479
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4480
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4481
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4482
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4483

    
4484
		$interface_channels = "";
4485
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4486

    
4487
		foreach ($interface_channels as $channel_line) {
4488
			$channel_line = explode(",", $channel_line);
4489
			if(!isset($wireless_channels[$channel_line[0]]))
4490
				$wireless_channels[$channel_line[0]] = $channel_line;
4491
		}
4492
	}
4493
	return($wireless_channels);
4494
}
4495

    
4496
/****f* interfaces/get_interface_mtu
4497
 * NAME
4498
 *   get_interface_mtu - Return the mtu of an interface
4499
 * RESULT
4500
 *   $tmp       - Returns the mtu of an interface
4501
 ******/
4502
function get_interface_mtu($interface) {
4503
        $mtu = pfSense_get_interface_addresses($interface);
4504
        return $mtu['mtu'];
4505
}
4506

    
4507
function get_interface_mac($interface) {
4508

    
4509
	$macinfo = pfSense_get_interface_addresses($interface);
4510
	return $macinfo["macaddr"];
4511
}
4512

    
4513
/****f* pfsense-utils/generate_random_mac_address
4514
 * NAME
4515
 *   generate_random_mac - generates a random mac address
4516
 * INPUTS
4517
 *   none
4518
 * RESULT
4519
 *   $mac - a random mac address
4520
 ******/
4521
function generate_random_mac_address() {
4522
        $mac = "02";
4523
        for($x=0; $x<5; $x++)
4524
                $mac .= ":" . dechex(rand(16, 255));
4525
        return $mac;
4526
}
4527

    
4528
/****f* interfaces/is_jumbo_capable
4529
 * NAME
4530
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4531
 * INPUTS
4532
 *   $int             - string containing interface name
4533
 * RESULT
4534
 *   boolean          - true or false
4535
 ******/
4536
function is_jumbo_capable($iface) {
4537

    
4538

    
4539
	$iface = trim($iface);
4540
	$capable = pfSense_get_interface_addresses($iface);
4541
	if (isset($capable['caps']['vlanmtu']))
4542
                return true;
4543

    
4544

    
4545

    
4546

    
4547

    
4548
	return false;
4549
}
4550

    
4551
function setup_pppoe_reset_file($pppif, $iface="") {
4552
	global $g;
4553
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4554

    
4555
	if(!empty($iface) && !empty($pppif)){
4556
		$cron_cmd = <<<EOD
4557
#!/bin/sh
4558
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4559
/usr/bin/logger -t pppoe{$iface} "PPPoE periodic reset executed on {$iface}"
4560

    
4561
EOD;
4562

    
4563
		file_put_contents($cron_file, $cron_cmd);
4564
		chmod($cron_file, 0700);
4565
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4566
	} else
4567
		unlink_if_exists($cron_file);
4568
}
4569

    
4570
function get_interface_default_mtu($type = "ethernet") {
4571
	switch ($type) {
4572
	case "gre":
4573
		return 1476;
4574
		break;
4575
	case "gif":
4576
		return 1280;
4577
		break;
4578
	case "tun":
4579
	case "vlan":
4580
	case "tap":
4581
	case "ethernet":
4582
	default:
4583
		return 1500;
4584
		break;
4585
	}
4586

    
4587
	/* Never reached */
4588
	return 1500;
4589
}
4590

    
4591
function get_vip_descr($ipaddress) {
4592
	global $config;
4593

    
4594
	foreach ($config['virtualip']['vip'] as $vip) {
4595
		if ($vip['subnet'] == $ipaddress) {
4596
			return ($vip['descr']);
4597
		}
4598
	}
4599
	return "";
4600
}
4601

    
4602
function interfaces_staticarp_configure($if) {
4603
	global $config, $g;
4604
	if(isset($config['system']['developerspew'])) {
4605
		$mt = microtime();
4606
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4607
	}
4608

    
4609
	$ifcfg = $config['interfaces'][$if];
4610

    
4611
	if (empty($if) || empty($ifcfg['if']))
4612
		return 0;
4613

    
4614
	/* Enable staticarp, if enabled */
4615
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4616
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4617
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4618
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4619

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

    
4623
			}
4624

    
4625
		}
4626
	} else {
4627
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4628
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4629
	}
4630

    
4631
	return 0;
4632
}
4633

    
4634
function get_failover_interface($interface) {
4635
	global $config;
4636
	/* shortcut to get_real_interface if we find it in the config */
4637
	if(is_array($config['interfaces'][$interface])) {
4638
		$wanif = get_real_interface($interface);
4639
		return $wanif;
4640
	}
4641

    
4642
	/* compare against gateway groups */
4643
	$a_groups = return_gateway_groups_array();
4644
	if(is_array($a_groups[$interface])) {
4645
		/* we found a gateway group, fetch the interface or vip */
4646
		if($a_groups[$interface][0]['vip'] <> "")
4647
			$wanif = $a_groups[$interface][0]['vip'];
4648
		else
4649
			$wanif = $a_groups[$interface][0]['int'];
4650
		
4651
		return $wanif;
4652
	}
4653
	/* fall through to get_real_interface */
4654
	$wanif = get_real_interface($interface);
4655
	return $wanif;
4656
}
4657

    
4658
?>
(26-26/68)