Project

General

Profile

Download (102 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_MODULE:	interfaces
41

    
42
*/
43

    
44
/* include all configuration functions */
45
require_once("globals.inc");
46
require_once("cmd_chain.inc");
47

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

    
57
/*
58
 * Return the interface array
59
 */
60
function get_interface_arr($flush = false) {
61
        global $interface_arr_cache;
62

    
63
        /* If the cache doesn't exist, build it */
64
        if (!isset($interface_arr_cache) or $flush)
65
                $interface_arr_cache = explode(" ", trim(`/sbin/ifconfig -l`));
66

    
67
        return $interface_arr_cache;
68
}
69

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

    
80
	$ints = get_interface_arr(true);
81
	if (in_array($interface, $ints))
82
		return true;
83
	else
84
		return false;
85
}
86

    
87
function interface_netgraph_needed($interface = "wan") {
88
	global $config;
89

    
90
	$found = false;
91
	if (!empty($config['pptpd']) &&
92
		$config['pptpd']['mode'] == "server")
93
		$found = true;
94
	if ($found == false && !empty($config['l2tp']) &&
95
		$config['l2tp']['mode'] == "server")
96
		$found = true;
97
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
98
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
99
			if ($pppoe['mode'] != "server")
100
				continue;
101
			if ($pppoe['interface'] == $interface)
102
				$found = true;
103
				break;
104
		}
105
	}
106
	if ($found == false && !empty($config['interfaces'][$interface])) {
107
		switch ($config['interfaces'][$interface]['ipaddr']) {
108
		case "ppp":
109
		case "pppoe":
110
		case "l2tp":
111
		case "pptp":
112
			$found = true;
113
			break;
114
		default:
115
			$found = false;
116
			break;
117
		}
118
	}
119

    
120
	$realif = get_real_interface($interface);
121
	if ($found == false)
122
		pfSense_ngctl_detach("{$realif}:", $realif);
123
	/* NOTE: We make sure for this on interface_ppps_configure()
124
	 *	no need to do it here agan.
125
	 *	else
126
	 *		pfSense_ngctl_attach(".", $realif);
127
	 */
128
}
129

    
130
function interfaces_loopback_configure() {
131
	if($g['booting'])
132
		echo "Configuring loopback interface...";
133
	pfSense_interface_setaddress("lo0", "127.0.0.1");
134
	interfaces_bring_up("lo0");
135
	if($g['booting'])
136
		echo "done.\n";
137
	return 0;
138
}
139

    
140
function interfaces_vlan_configure() {
141
	global $config, $g;
142
	if($g['booting'])
143
		echo "Configuring VLAN interfaces...";
144
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
145
		foreach ($config['vlans']['vlan'] as $vlan) {
146
			if(empty($vlan['vlanif']))
147
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
148
			/* XXX: Maybe we should report any errors?! */
149
			interface_vlan_configure($vlan);
150
		}
151
	}
152
	if($g['booting'])
153
		echo "done.\n";
154
}
155

    
156
function interface_vlan_configure(&$vlan) {
157
        global $config, $g;
158

    
159
	if (!is_array($vlan)) {
160
		log_error("VLAN: called with wrong options. Problems with config!");
161
		return;
162
	}
163
	$if = $vlan['if'];
164
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
165
	$tag = $vlan['tag'];
166

    
167
	if (empty($if)) {
168
		log_error("interface_vlan_confgure called with if undefined.");
169
		return;
170
	}
171

    
172
	/* make sure the parent interface is up */
173
	interfaces_bring_up($if);
174
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
175
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
176

    
177
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
178
		interface_bring_down($vlanif, true);
179
	} else {
180
		$tmpvlanif = pfSense_interface_create("vlan");
181
		pfSense_interface_rename($tmpvlanif, $vlanif);
182
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
183
	}
184

    
185
	pfSense_vlan_create($vlanif, $if, $tag);
186

    
187
	interfaces_bring_up($vlanif);
188

    
189
	/* invalidate interface cache */
190
	get_interface_arr(true);
191

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

    
195
	return $vlanif;
196
}
197

    
198
function interface_qinq_configure(&$vlan, $fd = NULL) {
199
        global $config, $g;
200

    
201
        if (!is_array($vlan)) {
202
                log_error("QinQ compat VLAN: called with wrong options. Problems with config!\n");
203
                return;
204
        }
205

    
206
        $qinqif = $vlan['if'];
207
        $tag = $vlan['tag'];
208
        if(empty($qinqif)) {
209
                log_error("interface_qinq_confgure called with if undefined.\n");
210
                return;
211
        }
212
	$vlanif = interface_vlan_configure($vlan);
213

    
214
        if ($fd == NULL) {
215
                $exec = true;
216
                $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
217
        } else
218
                $exec = false;
219
        /* make sure the parent is converted to ng_vlan(4) and is up */
220
        interfaces_bring_up($qinqif);
221

    
222
        if (!empty($vlanif) && does_interface_exist($vlanif)) {
223
                fwrite($fd, "shutdown {$qinqif}qinq:\n");
224
                exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
225
                if (empty($result)) {
226
                        fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
227
                        fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
228
                        fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
229
                }
230
        } else {
231
                fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
232
                fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
233
                fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
234
        }
235

    
236
        /* invalidate interface cache */
237
        get_interface_arr(true);
238

    
239
        if (!stristr($qinqif, "vlan"))
240
                mwexec("/sbin/ifconfig {$qinqif} promisc\n");
241

    
242
        $macaddr = get_interface_mac($qinqif);
243
        if (!empty($vlan['members'])) {
244
                $members = explode(" ", $vlan['members']);
245
                foreach ($members as $qtag) {
246
                        $qinq = array();
247
                        $qinq['tag'] = $qtag;
248
                        $qinq['if'] = $vlanif;
249
                        interface_qinq2_configure($qinq, $fd, $macaddr);
250
                }
251
        }
252
        if ($exec == true) {
253
                fclose($fd);
254
                mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
255
        }
256

    
257
        interfaces_bring_up($qinqif);
258
        if (!empty($vlan['members'])) {
259
                $members = explode(" ", $vlan['members']);
260
                foreach ($members as $qif)
261
                        interfaces_bring_up("{$vlanif}_{$qif}");
262
        }
263

    
264
        return $vlanif;
265
}
266

    
267
function interfaces_qinq_configure() {
268
	global $config, $g;
269
	if($g['booting'])
270
		echo "Configuring QinQ interfaces...";
271
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
272
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
273
			/* XXX: Maybe we should report any errors?! */
274
			interface_qinq_configure($qinq);
275
		}
276
	}
277
	if($g['booting'])
278
		echo "done.\n";
279
}
280

    
281
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
282
        global $config, $g;
283

    
284
        if (!is_array($qinq)) {
285
                log_error("QinQ compat VLAN: called with wrong options. Problems with config!\n");
286
                return;
287
        }
288

    
289
        $if = $qinq['if'];
290
        $tag = $qinq['tag'];
291
        $vlanif = "{$if}_{$tag}";
292
        if(empty($if)) {
293
                log_error("interface_qinq_confgure called with if undefined.\n");
294
                return;
295
        }
296

    
297
        fwrite($fd, "shutdown {$if}h{$tag}:\n");
298
        fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
299
        fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
300
        fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
301
        fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
302
        fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
303

    
304
        /* invalidate interface cache */
305
        get_interface_arr(true);
306

    
307
        return $vlanif;
308
}
309

    
310
function interfaces_create_wireless_clones() {
311
	global $config;
312

    
313
	if($g['booting'])
314
		echo "Creating other wireless clone interfaces...";
315
	if (is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
316
		foreach ($config['wireless']['clone'] as $clone) {
317
			if(empty($clone['cloneif']))
318
				continue;
319
			if(does_interface_exist($clone['cloneif']))
320
				continue;
321
			/* XXX: Maybe we should report any errors?! */
322
			if(interface_wireless_clone($clone['cloneif'], $clone))
323
				if($g['booting'])
324
					echo " " . $clone['cloneif'];
325
		}
326
	}
327
	if($g['booting'])
328
		echo " done.\n";
329
}
330

    
331
function interfaces_bridge_configure() {
332
        global $config;
333

    
334
        $i = 0;
335
        if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
336
                foreach ($config['bridges']['bridged'] as $bridge) {
337
                        if(empty($bridge['bridgeif']))
338
                                $bridge['bridgeif'] = "bridge{$i}";
339
                        /* XXX: Maybe we should report any errors?! */
340
                        interface_bridge_configure($bridge);
341
                        $i++;
342
                }
343
        }
344
}
345

    
346
function interface_bridge_configure(&$bridge) {
347
	global $config, $g;
348

    
349
	if (!is_array($bridge))
350
	        return -1;
351

    
352
	if (empty($bridge['members'])) {
353
		log_error("No members found on {$bridge['bridgeif']}");
354
		return -1;
355
	}
356

    
357
	$members = explode(',', $bridge['members']);
358
	if (!count($members))
359
		return -1;
360

    
361
	$checklist = get_configured_interface_list();
362

    
363
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
364
		pfSense_interface_destroy($bridge['bridgeif']);
365
		pfSense_interface_create($bridge['bridgeif']);
366
		$bridgeif = $bridge['bridgeif'];
367
	} else
368
		$bridgeif = pfSense_interface_create("bridge");
369

    
370
	/* Calculate smaller mtu and enforce it */
371
	$smallermtu = 0;
372
	$commonrx = true;
373
	$commontx = true;
374
	foreach ($members as $member) {
375
		$realif = get_real_interface($member);
376
		$opts = pfSense_get_interface_addresses($realif);
377
		$mtu = $opts['mtu'];
378
		if (!isset($opts['encaps']['txcsum']))
379
			$commontx = false;
380
		if (!isset($opts['encaps']['rxcsum']))
381
			$commonrx = false;
382
		if (!isset($opts['encaps']['tso4']))
383
			$commontso4 = false;
384
		if (!isset($opts['encaps']['tso6']))
385
			$commontso6 = false;
386
		if (!isset($opts['encaps']['lro']))
387
			$commonlro = false;
388
		if ($smallermtu == 0 && !empty($mtu))
389
			$smallermtu = $mtu;
390
		else if (!empty($mtu) && $mtu < $smallermtu)
391
			$smallermtu = $mtu;
392
	}
393
	 
394
	/* Just in case anything is not working well */
395
	if ($smallermtu == 0)
396
		$smallermtu = 1500; 
397

    
398
	$flags = 0;
399
	if ($commonrx === false)
400
		$flags |= IFCAP_RXCSUM;
401
	if ($commontx === false)
402
		$flags |= IFCAP_TXCSUM;
403
	if ($commontso4 === false)
404
		$flags |= IFCAP_TSO4;
405
	if ($commontso6 === false)
406
		$flags |= IFCAP_TSO6;
407
	if ($commonlro === false)
408
		$flags |= IFCAP_LRO;
409
		
410
	/* Add interfaces to bridge */
411
	foreach ($members as $member) {
412
		if (!array_key_exists($member, $checklist))
413
			continue;
414
		$realif1 = get_real_interface($member);
415
		$realif =  escapeshellarg($realif1);
416
		if (!$realif) {
417
			log_error("realif not defined in interfaces bridge - up");
418
			continue;
419
		}
420
		/* make sure the parent interface is up */
421
		pfSense_interface_mtu($realif1, $smallermtu);
422
		pfSense_interface_capabilities($realif1, -$flags);
423
		interfaces_bring_up($realif1);
424
		mwexec("/sbin/ifconfig {$bridgeif} addm {$realif}");	
425
	}
426

    
427
	if (isset($bridge['enablestp'])) {
428
		/* Choose spanning tree proto */
429
		mwexec("/sbin/ifconfig {$bridgeif} proto {$bridge['proto']}");	
430
		
431
		if (!empty($bridge['stp'])) {
432
			$stpifs = explode(',', $bridge['stp']);
433
			foreach ($stpifs as $stpif) {
434
				$realif = get_real_interface($stpif);
435
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
436
			}
437
		}
438
		if (!empty($bridge['maxage']))
439
			mwexec("/sbin/ifconfig {$bridgeif} maxage {$bridge['maxage']}");
440
		if (!empty($brige['fwdelay']))
441
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay {$bridge['fwdelay']}");
442
		if (!empty($brige['hellotime']))
443
                        mwexec("/sbin/ifconfig {$bridgeif} hellotime {$bridge['hellotime']}");
444
		if (!empty($brige['priority']))
445
                        mwexec("/sbin/ifconfig {$bridgeif} priority {$bridge['priority']}");
446
		if (!empty($brige['holdcount']))
447
                        mwexec("/sbin/ifconfig {$bridgeif} holdcnt {$bridge['holdcnt']}");
448
		if (!empty($bridge['ifpriority'])) {
449
			$pconfig = explode(",", $bridge['ifpriority']);
450
			$ifpriority = array();
451
			foreach ($pconfig as $cfg) {
452
				$embcfg = explode(":", $cfg);
453
				foreach ($embcfg as $key => $value)
454
					$ifpriority[$key] = $value;
455
			}
456
			foreach ($ifpriority as $key => $value) {
457
				$realif = get_real_interface($key);
458
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} {$value}"); 
459
			}
460
		}
461
		if (!empty($bridge['ifpathcost'])) {
462
			$pconfig = explode(",", $bridges['ifpathcost']);
463
			$ifpathcost = array();
464
			foreach ($pconfig as $cfg) {
465
				$embcfg = explode(":", $cfg);
466
				foreach ($embcfg as $key => $value)
467
					$ifpathcost[$key] = $value;
468
			}
469
			foreach ($ifpathcost as $key => $value) {
470
                        	$realif = get_real_interface($key);
471
                        	mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} {$value}");
472
                	}
473
		}
474
	}
475

    
476
	if ($bridge['maxaddr'] <> "")
477
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr {$bridge['maxaddr']}");
478
        if ($bridge['timeout'] <> "")
479
                mwexec("/sbin/ifconfig {$bridgeif} timeout {$bridge['timeout']}");
480
        if ($bridge['span'] <> "") {
481
		$realif = get_real_interface($bridge['span']);
482
                mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
483
	}
484
	if (!empty($bridge['edge'])) {
485
        	$edgeifs = explode(',', $bridge['edge']);
486
        	foreach ($edgeifs as $edgeif) {
487
			$realif = get_real_interface($edgeif);
488
                	mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
489
        	}
490
	}
491
	if (!empty($bridge['autoedge'])) {
492
        	$edgeifs = explode(',', $bridge['autoedge']);
493
        	foreach ($edgeifs as $edgeif) {
494
                	$realif = get_real_interface($edgeif);
495
                	mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
496
        	}
497
	}
498
	if (!empty($bridge['ptp'])) {
499
        	$ptpifs = explode(',', $bridge['ptp']);
500
        	foreach ($ptpifs as $ptpif) {
501
                	$realif = get_real_interface($ptpif);
502
                	mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
503
        	}
504
	}
505
	if (!empty($bridge['autoptp'])) {
506
        	$ptpifs = explode(',', $bridge['autoptp']);
507
        	foreach ($ptpifs as $ptpif) {
508
                	$realif = get_real_interface($ptpif);
509
                	mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
510
        	}
511
	}
512
	if (!empty($bridge['static'])) {
513
        	$stickyifs = explode(',', $bridge['static']);
514
        	foreach ($stickyifs as $stickyif) {
515
                	$realif = get_real_interface($stickyif);
516
                	mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
517
        	}
518
	}
519
	if (!empty($bridge['private'])) {
520
        	$privateifs = explode(',', $bridge['private']);
521
        	foreach ($privateifs as $privateif) {
522
                	$realif = get_real_interface($privateif);
523
               	 	mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
524
        	}
525
	}
526

    
527
	if($bridgeif)
528
		interfaces_bring_up($bridgeif);	
529
	else 
530
		log_error("bridgeif not defined -- could not bring interface up");
531

    
532
	return $bridgeif;
533
}
534

    
535
function interface_bridge_add_member($bridgeif, $interface) {
536

    
537
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
538
		return;
539

    
540
	$mtu = get_interface_mtu($brigeif);
541
	$mtum = get_interface_mtu($interface);
542
	
543
	if ($mtu != $mtum)
544
		pfSense_interface_mtu($interface, $mtu);
545

    
546
	$options = pfSense_get_interface_addresses($bridgeif);
547
	$flags = 0;
548
	if (!isset($options['encaps']['txcsum']))
549
		$flags |= IFCAP_TXCSUM;
550

    
551
	if (!isset($options['encaps']['rxcsum']))
552
		$flags |= IFCAP_RXCSUM;
553

    
554
	pfSense_interface_capabilities($interface, -$flags);
555

    
556
	interfaces_bring_up($interface);
557
	mwexec("/sbin/ifconfig {$bridgeif} addm {$interface}");
558
}
559

    
560
function interfaces_lagg_configure() 
561
{
562
        global $config, $g;
563
		if($g['booting']) 
564
			echo "Configuring LAGG interfaces...";
565
        $i = 0;
566
		if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
567
			foreach ($config['laggs']['lagg'] as $lagg) {
568
				if(empty($lagg['laggif']))
569
					$lagg['laggif'] = "lagg{$i}";
570
				/* XXX: Maybe we should report any errors?! */
571
				interface_lagg_configure($lagg);
572
				$i++;
573
			}
574
		}
575
		if($g['booting']) 
576
			echo "done.\n";
577
}
578

    
579
function interface_lagg_configure(&$lagg) {
580
        global $config, $g;
581

    
582
        if (!is_array($lagg))
583
		return -1;
584

    
585
	$members = explode(',', $lagg['members']);
586
	if (!count($members))
587
		return -1;
588
	
589
	$checklist = get_interface_list();
590

    
591
	if ($g['booting'] || !(empty($lagg['laggif']))) {
592
		pfSense_interface_destroy($lagg['laggif']);
593
		pfSense_interface_create($lagg['laggif']);
594
                $laggif = $lagg['laggif'];
595
        } else
596
		$laggif = pfSense_interface_create("lagg");
597

    
598
	/* Calculate smaller mtu and enforce it */
599
        $smallermtu = 0;
600
        foreach ($members as $member) {
601
		$opts = pfSense_get_interface_addresses($member);
602
                $mtu = $opts['mtu'];
603
		if (!isset($opts['encaps']['txcsum']))
604
                        $commontx = false;
605
                if (!isset($opts['encaps']['rxcsum']))
606
                        $commonrx = false;
607
		if (!isset($opts['encaps']['tso4']))
608
			$commontso4 = false;
609
		if (!isset($opts['encaps']['tso6']))
610
			$commontso6 = false;
611
		if (!isset($opts['encaps']['lro']))
612
			$commonlro = false;
613
		if ($smallermtu == 0 && !empty($mtu))
614
			$smallermtu = $mtu;
615
                else if (!empty($mtu) && $mtu < $smallermtu)
616
                        $smallermtu = $mtu;
617
        }
618

    
619
	/* Just in case anything is not working well */
620
        if ($smallermtu == 0)
621
                $smallermtu = 1500;
622

    
623
	$flags = 0;
624
        if ($commonrx === false)
625
                $flags |= IFCAP_RXCSUM;
626
        if ($commontx === false)
627
                $flags |= IFCAP_TXCSUM;
628
	if ($commontso4 === false)
629
                $flags |= IFCAP_TSO4;
630
        if ($commontso6 === false)
631
                $flags |= IFCAP_TSO6;
632
        if ($commonlro === false)
633
                $flags |= IFCAP_LRO;
634

    
635
	foreach ($members as $member) {
636
		if (!array_key_exists($member, $checklist))
637
			continue;
638
		/* make sure the parent interface is up */
639
		pfSense_interface_mtu($member, $smallermtu);
640
		pfSense_interface_capabilities($member, -$flags);
641
		interfaces_bring_up($member);
642
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
643
	}
644
	
645
	mwexec("/sbin/ifconfig {$laggif} laggproto {$lagg['proto']}");
646

    
647
	interfaces_bring_up($laggif);
648

    
649
	return $laggif;
650
}
651

    
652
function interfaces_gre_configure() {
653
        global $config;
654

    
655
        if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
656
                foreach ($config['gres']['gre'] as $i => $gre) {
657
                        if(empty($gre['greif']))
658
                                $gre['greif'] = "gre{$i}";
659
                        /* XXX: Maybe we should report any errors?! */
660
                        interface_gre_configure($gre);
661
                }
662
        }
663
}
664

    
665
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
666
function interface_gre_configure(&$gre, $grekey = "") {
667
        global $config, $g;
668

    
669
	if (!is_array($gre))
670
		return -1;
671

    
672
	$realif = get_real_interface($gre['if']);
673
	$realifip = get_interface_ip($gre['if']);
674

    
675
	/* make sure the parent interface is up */
676
	interfaces_bring_up($realif);
677

    
678
	if ($g['booting'] || !(empty($gre['greif']))) {
679
		pfSense_interface_destroy($gre['greif']);
680
		pfSense_interface_create($gre['greif']);
681
		$greif = $gre['greif'];
682
	} else
683
		$greif = pfSense_interface_create("gre");
684

    
685
	/* Do not change the order here for more see gre(4) NOTES section. */
686
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} {$gre['remote-addr']}");
687
	mwexec("/sbin/ifconfig {$greif} {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
688
	if (isset($gre['link0']) && $gre['link0'])
689
		pfSense_interface_flags($greif, IFF_LINK0);
690
	if (isset($gre['link1']) && $gre['link1'])
691
		pfSense_interface_flags($greif, IFF_LINK1);
692
	if (isset($gre['link2']) && $gre['link2'])
693
		pfSense_interface_flags($greif, IFF_LINK2);
694

    
695
	if($greif)
696
		interfaces_bring_up($greif);
697
	else 
698
		log_error("Could not bring greif up -- variable not defined.");
699

    
700
	if (isset($gre['link1']) && $gre['link1'])
701
		mwexec("/sbin/route add {$gre['tunnel-remote-addr']}/{$gre['tunnel-remote-net']} {$gre['tunnel-local-addr']}");
702
	file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
703

    
704
	return $greif;
705
}
706

    
707
function interfaces_gif_configure() {
708
	global $config;
709

    
710
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
711
		foreach ($config['gifs']['gif'] as $i => $gif) {
712
			if(empty($gif['gifif']))
713
				$gre['gifif'] = "gif{$i}";
714
			/* XXX: Maybe we should report any errors?! */
715
			interface_gif_configure($gif);
716
		}
717
	}
718
}
719

    
720
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
721
function interface_gif_configure(&$gif, $gifkey = "") {
722
	global $config, $g;
723

    
724
	if (!is_array($gif))
725
		return -1;
726

    
727
	$realif = get_real_interface($gif['if']);
728
	$realifip = get_interface_ip($gif['if']);
729

    
730
	/* make sure the parent interface is up */
731
	if($realif)
732
		interfaces_bring_up($realif);
733
	else 
734
		log_error("could not bring realif up -- variable not defined -- interface_gif_configure()");
735

    
736
	if ($g['booting'] || !(empty($gif['gifif']))) {
737
		pfSense_interface_destroy($gif['gifif']);
738
		pfSense_interface_create($gif['gifif']);
739
		$gifif = $gif['gifif'];
740
	} else
741
		$gifif = pfSense_interface_create("gif");
742

    
743
	/* Do not change the order here for more see gif(4) NOTES section. */
744
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} {$gif['remote-addr']}");
745
	mwexec("/sbin/ifconfig {$gifif} {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
746
	if (isset($gif['link0']) && $gif['link0'])
747
		pfSense_interface_flags($gifif, IFF_LINK0);
748
	if (isset($gif['link1']) && $gif['link1'])
749
		pfSense_interface_flags($gifif, IFF_LINK1);
750
	if($gifif)
751
		interfaces_bring_up($gifif);
752
	else
753
		log_error("could not bring gifif up -- variable not defined");
754

    
755
	/* XXX: Needed?! */
756
	//mwexec("/sbin/route add {$gif['tunnel-remote-addr']}/{$gif['tunnel-remote-net']} -iface {$gifif}");
757
	file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
758

    
759
	return $gifif;
760
}
761

    
762
function interfaces_configure() {
763
	global $config, $g;
764

    
765
	/* Set up our loopback interface */
766
	interfaces_loopback_configure();
767

    
768
	/* set up LAGG virtual interfaces */
769
	interfaces_lagg_configure();
770

    
771
	/* set up VLAN virtual interfaces */
772
	interfaces_vlan_configure();
773

    
774
	interfaces_qinq_configure();
775

    
776
	$iflist = get_configured_interface_with_descr();
777
	$delayed_list = array();
778
	$bridge_list = array();
779
	
780
	/* This is needed to speedup interfaces on bootup. */
781
	$reload = false;
782
	if ($g['booting'])
783
		$reload = true;
784

    
785
	foreach($iflist as $if => $ifname) {
786
		$realif = $config['interfaces'][$if]['if'];
787
		if (strstr($realif, "bridge")) 
788
			$bridge_list[$if] = $ifname;
789
		else if (strstr($realif, "gre"))
790
			$delayed_list[$if] = $ifname;
791
		else if (strstr($realif, "gif"))
792
			$delayed_list[$if] = $ifname;
793
		else if (strstr($realif, "ovpn")) {
794
			//echo "Delaying OpenVPN interface configuration...done.\n";
795
			continue;
796
		} else {
797
			if ($g['booting'])
798
				echo "Configuring {$ifname} interface...";
799
			if($g['debug'])
800
				log_error("Configuring {$ifname}");
801
			interface_configure($if, $reload);
802
			if ($g['booting']) 
803
				echo "done.\n";
804
		}
805
	}
806

    
807
	/* create the unconfigured wireless clones */
808
	interfaces_create_wireless_clones();
809

    
810
	/* set up GRE virtual interfaces */
811
	interfaces_gre_configure();
812

    
813
	/* set up GIF virtual interfaces */
814
	interfaces_gif_configure();
815
	
816
	foreach ($delayed_list as $if => $ifname) {
817
		if ($g['booting'])
818
			echo "Configuring {$ifname} interface...";
819
        	if ($g['debug'])
820
        		log_error("Configuring {$ifname}");
821

    
822
		interface_configure($if, $reload);
823

    
824
		if ($g['booting'])
825
			echo "done.\n";
826
	}
827

    
828
	/* set up BRIDGe virtual interfaces */
829
	interfaces_bridge_configure();
830

    
831
	foreach ($bridge_list as $if => $ifname) {
832
		if ($g['booting'])
833
			echo "Configuring {$ifname} interface...";
834
		if($g['debug'])
835
			log_error("Configuring {$ifname}");
836

    
837
		interface_configure($if, $reload);
838

    
839
		if ($g['booting'])
840
			echo "done.\n";
841
	}
842

    
843
	/* bring up vip interfaces */
844
	interfaces_vips_configure();
845

    
846
	/* configure interface groups */
847
	interfaces_group_setup();
848

    
849
	if (!$g['booting']) {
850
		/* reconfigure static routes (kernel may have deleted them) */
851
		system_routing_configure();
852

    
853
		/* reload IPsec tunnels */
854
		vpn_ipsec_configure();
855

    
856
		/* reload dhcpd (interface enabled/disabled status may have changed) */
857
		services_dhcpd_configure();
858

    
859
		/* restart dnsmasq */
860
		services_dnsmasq_configure();
861

    
862
		/* reload captive portal */
863
		captiveportal_init_rules();
864
	}
865

    
866
	return 0;
867
}
868

    
869
function interface_reconfigure($interface = "wan") {
870
	interface_bring_down($interface);
871
	interface_configure($interface, true);
872
}
873

    
874
function interface_vip_bring_down($vip) {
875
	global $g;
876

    
877
	switch ($vip['mode']) {
878
	case "proxyarp":
879
		$vipif = get_real_interface($vip['interface']);
880
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
881
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
882
		break;
883
	case "ipalias":
884
		$vipif = get_real_interface($vip['interface']);
885
		if(does_interface_exist($vipif))
886
			pfSense_interface_deladdress($vipif, $vip['subnet']);
887
		break;
888
	case "carp":
889
		$vipif = "vip" . $vip['vhid'];
890
		if(does_interface_exist($vipif)) 
891
			pfSense_interface_destroy($vipif);
892
		break;
893
	case "carpdev-dhcp":
894
		$vipif = "vip" . $vip['vhid'];
895
		if(does_interface_exist($vipif)) 
896
			pfSense_interface_destroy($vipif);
897
		break;
898
	}
899
}
900

    
901
function interface_bring_down($interface = "wan", $destroy = false) {
902
	global $config, $g;
903

    
904
	if (!isset($config['interfaces'][$interface]))
905
		return; 
906

    
907
	$ifcfg = $config['interfaces'][$interface];
908

    
909
	$realif = get_real_interface($interface);
910

    
911
	switch ($ifcfg['ipaddr']) {
912
	case "ppp":
913
	case "pppoe":
914
	case "pptp":
915
	case "l2tp":
916
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
917
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
918
				if ($realif == $ppp['if']) {
919
					if (file_exists("{$g['varrun_path']}/{$ifcfg['ipaddr']}_{$interface}.pid")) {
920
						killbypid("{$g['varrun_path']}/{$ifcfg['ipaddr']}_{$interface}.pid");
921
						sleep(5);
922
					}
923
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
924
					if (isset($ppp['ondemand']) && !$destroy)
925
						send_event("interface reconfigure {$interface}");
926
					break;
927
				}
928
			}
929
		}
930
		break;
931
	case "carpdev-dhcp":
932
		/* 
933
		 * NB: When carpdev gets enabled it would be better to be handled as all
934
		 *	   other interfaces! 
935
		 */
936
	case "dhcp":
937
		$pid = find_dhclient_process($realif);
938
		if($pid)
939
			mwexec("kill {$pid}");
940
		sleep(1);
941
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
942
		if(does_interface_exist("$realif")) {
943
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
944
			if ($destroy == true)
945
				pfSense_interface_flags($realif, -IFF_UP);
946
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
947
		}
948
		break;
949
	default:
950
		if(does_interface_exist("$realif")) {
951
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
952
			if ($destroy == true)
953
				pfSense_interface_flags($realif, -IFF_UP);
954
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
955
		}
956
		break;
957
	}
958

    
959
	/* remove interface up file if it exists */
960
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
961
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
962
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
963
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
964
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
965
	
966
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
967
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
968
	if (is_array($ifcfg['wireless'])) {
969
		mwexec(kill_hostapd($realif));
970
		mwexec(kill_wpasupplicant($realif));
971
	}
972

    
973
	if ($destroy == true) {
974
		if (preg_match("/^vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan/i", $realif))
975
			pfSense_interface_destroy($realif);
976
	}	
977

    
978
	return;
979
}
980

    
981
function interfaces_ptpid_used($ptpid) {
982
	global $config;
983

    
984
	if (is_array($config['ppps']['ppp']))
985
		foreach ($config['ppps']['ppp'] as & $settings)
986
			if ($ptpid == $settings['ptpid'])
987
				return true;
988

    
989
	return false;
990
}
991

    
992
function interfaces_ptpid_next() {
993

    
994
	$ptpid = 0;
995
	while(interfaces_ptpid_used($ptpid))
996
		$ptpid++;
997

    
998
	return $ptpid;
999
}
1000

    
1001
function getMPDCRONSettings($pppif_) {
1002
	global $config;
1003
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
1004
	if (is_array($config['cron']['item'])) {
1005
		for ($i = 0; $i < count($config['cron']['item']); $i++) {
1006
			$item = $config['cron']['item'][$i];
1007
			if (strpos($item['command'], $cron_cmd_file.$pppif_) !== false) {
1008
				return array("ID" => $i, "ITEM" => $item);
1009
			}
1010
		}
1011
	}
1012
	return NULL;
1013
}
1014

    
1015
function handle_pppoe_reset($post_array) {
1016
	global $config, $g;
1017

    
1018
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
1019

    
1020
	$pppif = $post_array['type'].$post_array['ptpid'];
1021
	if (!is_array($config['cron']['item'])) 
1022
		$config['cron']['item'] = array(); 
1023
	$itemhash = getMPDCRONSettings($pppif);
1024
	$item = $itemhash['ITEM'];
1025
	
1026
	// reset cron items if necessary and return
1027
	if (empty($post_array['pppoe-reset-type'])) {
1028
		if (isset($item))
1029
			unset($config['cron']['item'][$itemhash['ID']]);
1030
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1031
		return;
1032
	}
1033

    
1034
	if (empty($item)) 
1035
		$item = array();
1036
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1037
		$item['minute'] = $post_array['pppoe_resetminute'];
1038
		$item['hour'] = $post_array['pppoe_resethour'];
1039
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1040
			$date = explode("/", $post_array['pppoe_resetdate']);
1041
			$item['mday'] = $date[1];
1042
			$item['month'] = $date[0];
1043
		} else {
1044
			$item['mday'] = "*";
1045
			$item['month'] = "*";
1046
		}
1047
		$item['wday'] = "*";
1048
		$item['who'] = "root";
1049
		$item['command'] = $cron_cmd_file.$pppif;
1050
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1051
		switch ($post_array['pppoe_pr_preset_val']) {
1052
			case "monthly":
1053
				$item['minute'] = "0";
1054
				$item['hour'] = "0";
1055
				$item['mday'] = "1";
1056
				$item['month'] = "*";
1057
				$item['wday'] = "*";
1058
				$item['who'] = "root";
1059
				$item['command'] = $cron_cmd_file.$pppif;
1060
				break;
1061
	        case "weekly":
1062
				$item['minute'] = "0";
1063
				$item['hour'] = "0";
1064
				$item['mday'] = "*";
1065
				$item['month'] = "*";
1066
				$item['wday'] = "0";
1067
				$item['who'] = "root";
1068
				$item['command'] = $cron_cmd_file.$pppif;
1069
				break;
1070
			case "daily":
1071
				$item['minute'] = "0";
1072
				$item['hour'] = "0";
1073
				$item['mday'] = "*";
1074
				$item['month'] = "*";
1075
				$item['wday'] = "*";
1076
				$item['who'] = "root";
1077
				$item['command'] = $cron_cmd_file.$pppif;
1078
				break;
1079
			case "hourly":
1080
				$item['minute'] = "0";
1081
				$item['hour'] = "*";
1082
				$item['mday'] = "*";
1083
				$item['month'] = "*";
1084
				$item['wday'] = "*";
1085
				$item['who'] = "root";
1086
				$item['command'] = $cron_cmd_file.$pppif;
1087
				break;
1088
		} // end switch
1089
	} else {
1090
		/* test whether a cron item exists and unset() it if necessary */
1091
		$itemhash = getMPDCRONSettings($pppif);
1092
		$item = $itemhash['ITEM'];
1093
		if (isset($item))
1094
			unset($config['cron']['item'][$itemhash['ID']]); 
1095
	}// end if
1096
	if (isset($itemhash['ID'])) 
1097
		$config['cron']['item'][$itemhash['ID']] = $item;
1098
	else 
1099
		$config['cron']['item'][] = $item;
1100
}
1101

    
1102
/*	This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1103
*	It writes the mpd config file to /var/etc every time the link is opened.
1104
*/
1105

    
1106
function interface_ppps_configure($interface) {
1107
	global $config, $g;
1108
	
1109
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1110
	if(!is_dir("/var/spool/lock")) {
1111
		exec("/bin/mkdir -p /var/spool/lock");
1112
		exec("/bin/chmod a+rw /var/spool/lock/.");
1113
	}
1114
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files	
1115
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1116
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1117
		
1118
	$ifcfg = $config['interfaces'][$interface];
1119
	if (!isset($ifcfg['enable']))
1120
		return 0;
1121
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1122
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1123
			if ($ifcfg['if'] == $ppp['if'])
1124
				break;
1125
		}
1126
	}
1127
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1128
		log_error("Can't find PPP config for {$ifcfg['if']} in interface_ppps_configure().");
1129
		return 0;
1130
	}
1131
	$pppif = $ifcfg['if'];
1132
	if ($ppp['type'] == "ppp")
1133
		$type = "modem";
1134
	else
1135
		$type = $ppp['type'];
1136
	$upper_type = strtoupper($ppp['type']);	
1137
	
1138
	if($g['booting']) {
1139
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1140
		echo "starting {$pppif} link...";
1141
		// Do not re-configure the interface if we are booting and it's already been started
1142
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1143
			return 0;
1144
	}
1145
	
1146
	$ports = explode(',',$ppp['ports']);
1147
	if ($type != "modem") {
1148
		foreach ($ports as $pid => $port)
1149
			$ports[$pid] = get_real_interface($port);
1150
	}
1151
	$localips = explode(',',$ppp['localip']);
1152
	$gateways = explode(',',$ppp['gateway']);
1153
	$subnets = explode(',',$ppp['subnet']);
1154
	
1155
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1156
	to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1157
	*/
1158
	foreach($ports as $pid => $port){
1159
		pfSense_ngctl_attach(".", $port);
1160
		switch ($ppp['type']) {
1161
			case "pppoe": 
1162
				/* Bring the parent interface up */
1163
				interfaces_bring_up($port);
1164
				break;
1165
			case "pptp":
1166
			case "l2tp":
1167
				/* configure interface */
1168
				if(is_ipaddr($localips[$pid])){
1169
					// Manually configure interface IP/subnet
1170
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1171
					interfaces_bring_up($port);
1172
				} else if (empty($localips[$pid]))
1173
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1174
				
1175
				if(!is_ipaddr($localips[$pid])){
1176
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure.");
1177
					return 0;
1178
				}
1179
				/* XXX: This needs to go away soon! [It's commented out!] */
1180
				/* Configure the gateway (remote IP ) */
1181
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1182
					/* XXX: Fix later 
1183
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1184
					if(!is_ipaddr($gateways[$pid])) {
1185
						log_error("Could not get a valid Gateway IP from {$port} via DNS in interfaces_ppps_configure.");
1186
						return 0;
1187
					}
1188
					*/
1189
				}
1190
				if(!is_ipaddr($gateways[$pid])){
1191
					log_error("Could not get a PPTP/L2TP Remote IP address from {$dhcp_gateway} for {$gway} in interfaces_ppps_configure.");
1192
					return 0;
1193
				}
1194
				break;
1195
			case "ppp":
1196
				if (!file_exists("{$port}")) {
1197
					log_error("Device {$port} does not exist. PPP link cannot start without the modem device.");
1198
					return 0;
1199
				}
1200
				break;
1201
			default:
1202
				log_error("Unkown {$type} configured as ppp interface.");
1203
				break;
1204
		}
1205
	}
1206
	
1207
	if (is_array($ports) && count($ports) > 1)
1208
		$multilink = "enable";
1209
	else
1210
		$multilink = "disable";
1211
	
1212
	if ($type == "modem"){
1213
		if (is_ipaddr($ppp['localip']))
1214
			$localip = $ppp['localip'];
1215
		else
1216
			$localip = '0.0.0.0';
1217

    
1218
		if (is_ipaddr($ppp['gateway']))
1219
			$gateway = $ppp['gateway'];
1220
		else
1221
			$gateway = "10.64.64.{$pppid}";
1222
		$ranges = "{$localip}/0 {$gateway}/0";
1223
		
1224
		if (empty($ppp['apnum']))	
1225
			$ppp['apnum'] = 1;
1226
	} else
1227
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1228

    
1229
	if (isset($ppp['ondemand'])) 
1230
		$ondemand = "enable";
1231
	else
1232
		$ondemand = "disable";
1233
	if (!isset($ppp['idletimeout']))
1234
		$ppp['idletimeout'] = 0;
1235

    
1236
	if (empty($ppp['username']) && $type == "modem"){
1237
		$ppp['username'] = "user";
1238
		$ppp['password'] = "none";
1239
	}
1240
	if (empty($ppp['password']) && $type == "modem")
1241
		$passwd = "none";
1242
	else
1243
		$passwd = base64_decode($ppp['password']);
1244

    
1245
	$bandwidths = explode(',',$ppp['bandwidth']);
1246
	$mtus = explode(',',$ppp['mtu']);
1247
	$mrus = explode(',',$ppp['mru']);
1248

    
1249
	if (isset($ppp['mrru']))
1250
		$mrrus = explode(',',$ppp['mrru']);
1251

    
1252
	// Construct the mpd.conf file
1253
	$mpdconf = <<<EOD
1254
startup:
1255
	# configure the console
1256
	set console close
1257
	# configure the web server
1258
	set web close
1259

    
1260
default:
1261
{$ppp['type']}client:
1262
	create bundle static {$interface}
1263
	set iface name {$pppif}
1264

    
1265
EOD;
1266
	$setdefaultgw = false;
1267
	$founddefaultgw = false;
1268
	if (is_array($config['gateways']['gateway_item'])) {
1269
		foreach($config['gateways']['gateway_item'] as $gateway) {
1270
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1271
				$setdefaultgw = true;
1272
				break;
1273
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1274
				$founddefaultgw = true;
1275
				break;
1276
			}
1277
		}
1278
	}
1279
	
1280
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1281
		$setdefaultgw = true;
1282
		$mpdconf .= <<<EOD
1283
	set iface route default
1284

    
1285
EOD;
1286
	}
1287
	$mpdconf .= <<<EOD
1288
	set iface {$ondemand} on-demand
1289
	set iface idle {$ppp['idletimeout']}
1290

    
1291
EOD;
1292

    
1293
	if (isset($ppp['ondemand']))
1294
		$mpdconf .= <<<EOD
1295
	set iface addrs 10.10.1.1 10.10.1.2
1296

    
1297
EOD;
1298
	
1299
	if (isset($ppp['tcpmssfix']))
1300
		$tcpmss = "disable";
1301
	else
1302
		$tcpmss = "enable";
1303
		$mpdconf .= <<<EOD
1304
	set iface {$tcpmss} tcpmssfix
1305

    
1306
EOD;
1307

    
1308
	$mpdconf .= <<<EOD
1309
	set iface up-script /usr/local/sbin/ppp-linkup
1310
	set iface down-script /usr/local/sbin/ppp-linkdown
1311
	set ipcp ranges {$ranges}
1312

    
1313
EOD;
1314
	if (isset($ppp['vjcomp']))
1315
		$mpdconf .= <<<EOD
1316
	set ipcp no vjcomp
1317

    
1318
EOD;
1319

    
1320
	if (isset($config['system']['dnsallowoverride']))
1321
		$mpdconf .= <<<EOD
1322
	set ipcp enable req-pri-dns
1323
	set ipcp enable req-sec-dns
1324

    
1325
EOD;
1326
	if (!isset($ppp['verbose_log']))
1327
		$mpdconf .= <<<EOD
1328
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1329

    
1330
EOD;
1331
	foreach($ports as $pid => $port){
1332
		$port = get_real_interface($port);
1333
		$mpdconf .= <<<EOD
1334

    
1335
	create link static {$interface}_link{$pid} {$type}
1336
	set link action bundle {$interface}
1337
	set link {$multilink} multilink
1338
	set link keep-alive 10 60
1339
	set link max-redial 0
1340

    
1341
EOD;
1342
		if (isset($ppp['shortseq']))
1343
			$mpdconf .= <<<EOD
1344
	set link no shortseq
1345

    
1346
EOD;
1347

    
1348
		if (isset($ppp['acfcomp']))
1349
			$mpdconf .= <<<EOD
1350
	set link no acfcomp
1351

    
1352
EOD;
1353

    
1354
		if (isset($ppp['protocomp']))
1355
			$mpdconf .= <<<EOD
1356
	set link no protocomp
1357

    
1358
EOD;
1359

    
1360
		$mpdconf .= <<<EOD
1361
	set link disable chap pap
1362
	set link accept chap pap eap
1363
	set link disable incoming
1364

    
1365
EOD;
1366

    
1367

    
1368
		if (!empty($bandwidths[$pid]))
1369
			$mpdconf .= <<<EOD
1370
	set link bandwidth {$bandwidths[$pid]}
1371

    
1372
EOD;
1373

    
1374
		if (empty($mtus[$pid]))
1375
			$mtus[$pid] = "1492";
1376
			$mpdconf .= <<<EOD
1377
	set link mtu {$mtus[$pid]}
1378

    
1379
EOD;
1380

    
1381
		if (!empty($mrus[$pid]))
1382
			$mpdconf .= <<<EOD
1383
	set link mru {$mrus[$pid]}
1384

    
1385
EOD;
1386

    
1387
		if (!empty($mrrus[$pid]))
1388
			$mpdconf .= <<<EOD
1389
	set link mrru {$mrrus[$pid]}
1390

    
1391
EOD;
1392

    
1393
		$mpdconf .= <<<EOD
1394
	set auth authname "{$ppp['username']}"
1395
	set auth password {$passwd}
1396

    
1397
EOD;
1398
		if ($type == "modem") {
1399
			$mpdconf .= <<<EOD
1400
	set modem device {$ppp['ports']}
1401
	set modem script DialPeer
1402
	set modem idle-script Ringback
1403
	set modem watch -cd
1404
	set modem var \$DialPrefix "DT"
1405
	set modem var \$Telephone "{$ppp['phone']}"
1406

    
1407
EOD;
1408
		}
1409
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1410
			$mpdconf .= <<<EOD
1411
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1412

    
1413
EOD;
1414
		}
1415
		if (isset($ppp['initstr']) && $type == "modem") {
1416
			$initstr = base64_decode($ppp['initstr']);
1417
			$mpdconf .= <<<EOD
1418
	set modem var \$InitString "{$initstr}"
1419

    
1420
EOD;
1421
		}
1422
		if (isset($ppp['simpin']) && $type == "modem") {
1423
			$mpdconf .= <<<EOD
1424
	set modem var \$SimPin "{$ppp['simpin']}"
1425
	set modem var \$PinWait "{$ppp['pin-wait']}"
1426

    
1427
EOD;
1428
		}
1429
		if (isset($ppp['apn']) && $type == "modem") {
1430
			$mpdconf .= <<<EOD
1431
	set modem var \$APN "{$ppp['apn']}"
1432
	set modem var \$APNum "{$ppp['apnum']}"
1433

    
1434
EOD;
1435
		}
1436
		if (isset($ppp['provider']) && $type == "pppoe") {
1437
			$mpdconf .= <<<EOD
1438
	set pppoe service "{$ppp['provider']}"
1439

    
1440
EOD;
1441
		}
1442
		if ($type == "pppoe")
1443
			$mpdconf .= <<<EOD
1444
	set pppoe iface {$port}
1445

    
1446
EOD;
1447

    
1448
		if ($type == "pptp" || $type == "l2tp") {
1449
			$mpdconf .= <<<EOD
1450
	set {$type} self {$localips[$pid]}
1451
	set {$type} peer {$gateways[$pid]}
1452
	set {$type} disable windowing
1453

    
1454
EOD;
1455
		}
1456
		
1457
		$mpdconf .= "\topen\r\n";
1458
	} //end foreach($port)
1459

    
1460

    
1461
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1462
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1463
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1464
	else {
1465
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1466
		if (!$fd) {
1467
			log_error("Error: cannot open mpd_{$interface}.conf in interface_ppps_configure().\n");
1468
			return 0;
1469
		}
1470
		// Write out mpd_ppp.conf
1471
		fwrite($fd, $mpdconf);
1472
		fclose($fd);
1473
	}
1474

    
1475
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1476
	if (isset($ppp['uptime'])) {
1477
		if (!file_exists("/conf/{$pppif}.log")) {
1478
			conf_mount_rw();
1479
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1480
			conf_mount_ro();
1481
		}
1482
	} else {
1483
		if (file_exists("/conf/{$pppif}.log")) {
1484
			conf_mount_rw();
1485
			mwexec("rm -f /conf/{$pppif}.log");
1486
			conf_mount_ro();
1487
		}
1488
	}
1489

    
1490
	/* fire up mpd */
1491
	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");
1492

    
1493
	// Check for PPPoE periodic reset request 
1494
	if ($type == "pppoe") {
1495
		if (isset($ppp['pppoe-reset-type']))
1496
			setup_pppoe_reset_file($ppp['if'], $interface);
1497
		else
1498
			setup_pppoe_reset_file($ppp['if']);
1499
	}
1500

    
1501
	return 1;
1502
}
1503

    
1504
function interfaces_carp_setup() {
1505
	global $g, $config;
1506

    
1507
	$balanacing = "";
1508
	$pfsyncinterface = "";
1509
	$pfsyncenabled = "";
1510
	if(isset($config['system']['developerspew'])) {
1511
		$mt = microtime();
1512
		echo "interfaces_carp_setup() being called $mt\n";
1513
	}
1514

    
1515
	// Prepare CmdCHAIN that will be used to execute commands.
1516
	$cmdchain = new CmdCHAIN();	
1517

    
1518
	if ($g['booting']) {
1519
		echo "Configuring CARP settings...";
1520
		mute_kernel_msgs();
1521
	}
1522

    
1523
	/* suck in configuration items */
1524
	if($config['installedpackages']['carpsettings']) {
1525
		if($config['installedpackages']['carpsettings']['config']) {
1526
			foreach($config['installedpackages']['carpsettings']['config'] as $carp) {
1527
				$pfsyncenabled = $carp['pfsyncenabled'];
1528
				$balanacing = $carp['balancing'];
1529
				$pfsyncinterface = $carp['pfsyncinterface'];
1530
				$pfsyncpeerip = $carp['pfsyncpeerip'];
1531
			}
1532
		}
1533
	} else {
1534
		unset($pfsyncinterface);
1535
		unset($balanacing);
1536
		unset($pfsyncenabled);
1537
	}
1538

    
1539
	$cmdchain->add("Allow CARP", "/sbin/sysctl net.inet.carp.allow=1", true);			
1540
	if($balanacing) {
1541
		$cmdchain->add("Enable CARP ARP-balancing", "/sbin/sysctl net.inet.carp.arpbalance=1", true);
1542
		$cmdchain->add("Disallow CARP preemption", "/sbin/sysctl net.inet.carp.preempt=0", true);
1543
	} else
1544
		$cmdchain->add("Enable CARP preemption", "/sbin/sysctl net.inet.carp.preempt=1", true);		
1545

    
1546
	$cmdchain->add("Enable CARP logging", "/sbin/sysctl net.inet.carp.log=1", true);
1547
	if (!empty($pfsyncinterface))
1548
		$carp_sync_int = get_real_interface($pfsyncinterface);
1549

    
1550
	if($g['booting']) {
1551
		/*    install rules to alllow pfsync to sync up during boot
1552
		 *    carp interfaces will remain down until the bootup sequence finishes
1553
		 */
1554
		$fd = fopen("{$g['tmp_path']}/rules.boot", "w");
1555
		if ($fd) {
1556
			fwrite($fd, "pass quick proto carp all keep state\n");
1557
			fwrite($fd, "pass quick proto pfsync all\n");
1558
			fwrite($fd, "pass out quick from any to any keep state\n");
1559
			fclose($fd);
1560
			mwexec("/sbin/pfctl -f {$g['tmp_path']}/rules.boot");
1561
		} else
1562
			log_error("Could not create rules.boot file!");
1563
	}
1564

    
1565
	/* setup pfsync interface */
1566
	if($carp_sync_int and $pfsyncenabled) {
1567
		if (is_ipaddr($pfsyncpeerip))
1568
			$cmdchain->add("Bring up pfsync0 syncpeer", "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} syncpeer {$pfsyncpeerip} up", false);						
1569
		else
1570
			$cmdchain->add("Bring up pfsync0 syncdev", "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} up", false);			
1571
	} else
1572
		$cmdchain->add("Bring up pfsync0", "/sbin/ifconfig pfsync0 syncdev lo0 up", false);						
1573

    
1574
	if($config['virtualip']['vip'])
1575
		$cmdchain->add("Allow CARP.", "/sbin/sysctl net.inet.carp.allow=1", true);				
1576
	else
1577
		$cmdchain->add("Disallow CARP.", "/sbin/sysctl net.inet.carp.allow=0", true);		
1578
	
1579
	if($g['debug'])
1580
		$cmdchain->setdebug(); // optional for verbose logging
1581

    
1582
	$cmdchain->execute();
1583
	$cmdchain->clear();
1584

    
1585
	if ($g['booting']) {
1586
		unmute_kernel_msgs();
1587
		echo "done.\n";
1588
	}
1589
}
1590

    
1591
function interface_proxyarp_configure($interface = "") {
1592
	global $config, $g;
1593
	if(isset($config['system']['developerspew'])) {
1594
		$mt = microtime();
1595
		echo "interface_proxyarp_configure() being called $mt\n";
1596
	}
1597

    
1598
	/* kill any running choparp */
1599
	if (empty($interface))
1600
		killbyname("choparp");
1601
	else {
1602
		$vipif = get_real_interface($interface);
1603
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1604
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1605
	}
1606

    
1607
	$paa = array();
1608
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1609

    
1610
		/* group by interface */
1611
		foreach ($config['virtualip']['vip'] as $vipent) {
1612
			if ($vipent['mode'] === "proxyarp") {
1613
				if ($vipent['interface'])
1614
					$proxyif = $vipent['interface'];
1615
				else
1616
					$proxyif = "wan";
1617
				
1618
				if (!empty($interface) && $interface != $proxyif)
1619
					continue;
1620

    
1621
				if (!is_array($paa[$proxyif]))
1622
					$paa[$proxyif] = array();
1623

    
1624
				$paa[$proxyif][] = $vipent;
1625
			}
1626
		}
1627
	}
1628

    
1629
	if (!empty($interface)) {
1630
		if (is_array($paa[$interface])) {
1631
			$paaifip = get_interface_ip($interface);
1632
                        if (!is_ipaddr($paaifip))
1633
                                return;
1634
                        $args = get_real_interface($interface) . " auto";
1635
                        foreach ($paa[$interface] as $paent) {
1636
                                if (isset($paent['subnet']))
1637
                                        $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1638
                                else if (isset($paent['range']))
1639
                                        $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1640
                        }
1641
                        mwexec_bg("/usr/local/sbin/choparp " . $args);	
1642
		}
1643
	} else if (count($paa) > 0) {
1644
		foreach ($paa as $paif => $paents)  {
1645
			$paaifip = get_interface_ip($paif);
1646
			if (!is_ipaddr($paaifip))
1647
				continue;
1648
			$args = get_real_interface($paif) . " auto";
1649
			foreach ($paents as $paent) {
1650
				if (isset($paent['subnet']))
1651
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1652
				else if (isset($paent['range']))
1653
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1654
			}
1655
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1656
		}
1657
	}
1658
}
1659

    
1660
function interfaces_vips_configure($interface = "") {
1661
	global $g, $config;
1662
	if(isset($config['system']['developerspew'])) {
1663
		$mt = microtime();
1664
		echo "interfaces_vips_configure() being called $mt\n";
1665
	}
1666
	$paa = array();
1667
	if(is_array($config['virtualip']['vip'])) {
1668
		$carp_setuped = false;
1669
		$anyproxyarp = false;
1670
		foreach ($config['virtualip']['vip'] as $vip) {
1671
			switch ($vip['mode']) {
1672
			case "proxyarp":
1673
				/* nothing it is handled on interface_proxyarp_configure() */
1674
				if ($interface <> "" && $vip['interface'] <> $interface)
1675
					continue;
1676
				$anyproxyarp = true;
1677
				break;
1678
			case "ipalias":
1679
				if ($interface <> "" && $vip['interface'] <> $interface)
1680
					continue;
1681
				interface_ipalias_configure(&$vip);
1682
				break;
1683
			case "carp":
1684
				if ($interface <> "" && $vip['interface'] <> $interface)
1685
					continue;
1686
				if ($carp_setuped == false) {
1687
					interfaces_carp_setup();
1688
					$carp_setuped = true;
1689
				}
1690
				interface_carp_configure($vip);
1691
				break;
1692
			case "carpdev-dhcp":
1693
				if ($interface <> "" && $vip['interface'] <> $interface)
1694
					continue;
1695
				interface_carpdev_configure($vip);
1696
				break;
1697
			}
1698
		}
1699
		
1700
		if ($anyproxyarp == true)
1701
			interface_proxyarp_configure();
1702
	}
1703
}
1704

    
1705
function interface_ipalias_configure(&$vip) {
1706

    
1707
	if ($vip['mode'] == "ipalias") {
1708
		$if = get_real_interface($vip['interface']);
1709
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $vip['subnet'] . "/" . escapeshellarg($vip['subnet_bits']) . " alias");
1710
	}
1711
}
1712

    
1713
function interface_reload_carps($cif) {
1714
	global $config;
1715

    
1716
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
1717
	if (empty($carpifs))
1718
		return;
1719

    
1720
	$carps = explode(" ", $carpifs);
1721
	if(is_array($config['virtualip']['vip'])) {
1722
		$viparr = &$config['virtualip']['vip'];
1723
		foreach ($viparr as $vip) {
1724
			if (in_array($vip['carpif'], $carps)) {
1725
				switch ($vip['mode']) {
1726
				case "carp":
1727
					interface_vip_bring_down($vip);
1728
					sleep(1);
1729
					interface_carp_configure($vip);
1730
					break;
1731
				case "carpdev-dhcp":
1732
					interface_vip_bring_down($vip);
1733
					sleep(1);
1734
					interface_carpdev_configure($vip);
1735
					break;
1736
				case "ipalias":
1737
					interface_vip_bring_down($vip);
1738
					sleep(1);
1739
					interface_ipalias_configure($vip);
1740
					break;
1741
				}
1742
			}
1743
		}
1744
	}
1745
}
1746

    
1747
function interface_carp_configure(&$vip) {
1748
	global $config, $g;
1749
	if(isset($config['system']['developerspew'])) {
1750
		$mt = microtime();
1751
		echo "interface_carp_configure() being called $mt\n";
1752
	}
1753

    
1754
	if ($vip['mode'] != "carp")
1755
		return;
1756

    
1757
	$vip_password = $vip['password'];
1758
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
1759
	if ($vip['password'] != "")
1760
		$password = " pass {$vip_password}";
1761

    
1762
	// set the vip interface to the vhid
1763
	$vipif = "vip{$vip['vhid']}";
1764

    
1765
	/*
1766
	 * ensure the interface containing the VIP really exists
1767
 	 * prevents a panic if the interface is missing or invalid
1768
	 */
1769
	$realif = get_real_interface($vip['interface']);
1770
	if (!does_interface_exist($realif)) {
1771
		file_notice("CARP", "Interface specified for the virtual IP address {$vip['subnet']} does not exist. Skipping this VIP.", "Firewall: Virtual IP", "");
1772
		return;
1773
	}
1774

    
1775
	/* Ensure CARP IP really exists prior to loading up. */
1776
	$ww_subnet_ip = find_interface_ip($realif);
1777
	$ww_subnet_bits = find_interface_subnet($realif);
1778
	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'])) {
1779
		file_notice("CARP", "Sorry but we could not find a matching real interface subnet for the virtual IP address {$vip['subnet']}.", "Firewall: Virtual IP", "");
1780
		return;
1781
	}
1782

    
1783
	/* create the carp interface and setup */
1784
	if (does_interface_exist($vipif)) {
1785
		pfSense_interface_flags($vipif, -IFF_UP);
1786
	} else {
1787
		$carpif = pfSense_interface_create("carp");
1788
		pfSense_interface_rename($carpif, $vipif);
1789
		pfSense_ngctl_name("{$carpif}:", $vipif);
1790
	}
1791

    
1792
	/* invalidate interface cache */
1793
	get_interface_arr(true);
1794

    
1795
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
1796
	mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} advbase {$vip['advbase']} {$password}");
1797

    
1798
	interfaces_bring_up($vipif);
1799
	
1800
	return $vipif;
1801
}
1802

    
1803
function interface_carpdev_configure(&$vip) {
1804
	global $g;
1805

    
1806
	if ($vip['mode'] != "carpdev-dhcp")
1807
		return;
1808

    
1809
	$vip_password = $vip['password'];
1810
	$vip_password = str_replace(" ", "", $vip_password);
1811
	if($vip['password'] != "")
1812
		$password = " pass \"" . $vip_password . "\"";
1813

    
1814
	if (empty($vip['interface']))
1815
		return;
1816

    
1817
	$vipif = "vip" . $vip['vhid'];
1818
	$realif = get_real_interface($vip['interface']);
1819
	interfaces_bring_up($realif);
1820
	/*
1821
	 * ensure the interface containing the VIP really exists
1822
	 * prevents a panic if the interface is missing or invalid
1823
	 */
1824
	if (!does_interface_exist($realif)) {
1825
		file_notice("CARP", "Interface specified for the virtual IP address {$vip['subnet']} does not exist. Skipping this VIP.", "Firewall: Virtual IP", "");
1826
		return;
1827
	}
1828

    
1829
	if (does_interface_exist($vipif)) {
1830
		interface_bring_down($vipif);
1831
	} else {
1832
		$carpdevif = exec("/sbin/ifconfig carp create");
1833
		mwexec("/sbin/ifconfig {$carpdevif} name {$vipif}");
1834
		pfSense_ngctl_name("{$carpdevif}:", $vipif);
1835
	}
1836

    
1837
	mwexec("/sbin/ifconfig {$vipif} carpdev {$realif} vhid {$vip['vhid']} advskew {$vip['advskew']} advbase {$vip['advbase']} {$password}");
1838
	interfaces_bring_up($vipif);
1839

    
1840
	/*
1841
	 * XXX: BIG HACK but carpdev needs ip services active
1842
	 *      before even starting something as dhclient.
1843
	 *      I do not know if this is a feature or a bug
1844
	 *      but better than track it make it work ;) .
1845
	 */
1846
	//$fakeiptouse = "10.254.254." . ($carp_instances_counter+1);
1847
	//$cmdchain->add("CarpDEV hack", "/sbin/ifconfig {$carpint} inet {$fakeiptouse}", false);
1848

    
1849
	/* generate dhclient_wan.conf */
1850
	$fd = fopen("{$g['varetc_path']}/dhclient_{$vipif}.conf", "w");
1851
	if ($fd) {
1852
		$dhclientconf = "";
1853

    
1854
		$dhclientconf .= <<<EOD
1855
interface "{$vipif}" {
1856
timeout 60;
1857
retry 1;
1858
select-timeout 0;
1859
initial-interval 1;
1860
script "/sbin/dhclient-script";
1861
}
1862

    
1863
EOD;
1864

    
1865
		fwrite($fd, $dhclientconf);
1866
		fclose($fd);
1867

    
1868
		/* fire up dhclient */
1869
		mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$vipif}.conf {$vipif} >{$g['tmp_path']}/{$vipif}_output 2>{$g['tmp_path']}/{$vipif}_error_output", false);
1870
	} else {
1871
		log_error("Error: cannot open dhclient_{$vipif}.conf in interfaces_carpdev_configure() for writing.\n");
1872
		mwexec("/sbin/dhclient -b {$vipif}");
1873
	}
1874

    
1875
	return $vipif;
1876
}
1877

    
1878
function interface_wireless_clone($realif, $wlcfg) {
1879
	global $config, $g;
1880
	/*   Check to see if interface has been cloned as of yet.  
1881
	 *   If it has not been cloned then go ahead and clone it.
1882
	 */
1883
	$needs_clone = false;
1884
	if(is_array($wlcfg['wireless']))
1885
		$wlcfg_mode = $wlcfg['wireless']['mode'];
1886
	else
1887
		$wlcfg_mode = $wlcfg['mode'];
1888
	switch($wlcfg_mode) {
1889
		 case "hostap":
1890
			$mode = "wlanmode hostap";
1891
			break;
1892
		 case "adhoc":
1893
			$mode = "wlanmode adhoc";
1894
			break;
1895
		 default:
1896
			$mode = "";
1897
			break;
1898
	}
1899
	$baseif = interface_get_wireless_base($wlcfg['if']);
1900
	if(does_interface_exist($realif)) {
1901
		exec("/sbin/ifconfig {$realif}", $output, $ret);
1902
		$ifconfig_str = implode($output);
1903
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
1904
			log_error("Interface {$realif} changed to hostap mode");
1905
			$needs_clone = true;
1906
		}
1907
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
1908
			log_error("Interface {$realif} changed to adhoc mode");
1909
			$needs_clone = true;
1910
		}
1911
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
1912
			log_error("Interface {$realif} changed to infrastructure mode");
1913
			$needs_clone = true;
1914
		}
1915
	} else {
1916
		$needs_clone = true;
1917
	}
1918

    
1919
	if($needs_clone == true) {
1920
		/* remove previous instance if it exists */
1921
		if(does_interface_exist($realif))
1922
			pfSense_interface_destroy($realif);
1923

    
1924
		log_error("Cloning new wireless interface {$realif}");
1925
		// Create the new wlan interface. FreeBSD returns the new interface name.
1926
		// example:  wlan2
1927
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
1928
		if($ret <> 0) {
1929
			log_error("Failed to clone interface {$baseif} with error code {$ret}, output {$out[0]}");
1930
			return false;
1931
		}
1932
		$newif = trim($out[0]);
1933
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
1934
		pfSense_interface_rename($newif, $realif);
1935
		// FIXME: not sure what ngctl is for. Doesn't work.
1936
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
1937
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
1938
	}
1939
	return true;
1940
}
1941

    
1942
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
1943
	global $config, $g;
1944

    
1945
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
1946
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
1947
	                         'regdomain', 'regcountry', 'reglocation');
1948

    
1949
	if(!is_interface_wireless($ifcfg['if']))
1950
		return;
1951

    
1952
	$baseif = interface_get_wireless_base($ifcfg['if']);
1953

    
1954
	// Sync shared settings for assigned clones
1955
	$iflist = get_configured_interface_list(false, true);
1956
	foreach ($iflist as $if) {
1957
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
1958
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
1959
				foreach ($shared_settings as $setting) {
1960
					if ($sync_changes) {
1961
						if (isset($ifcfg['wireless'][$setting]))
1962
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
1963
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
1964
							unset($config['interfaces'][$if]['wireless'][$setting]);
1965
					} else {
1966
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
1967
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
1968
						else if (isset($ifcfg['wireless'][$setting]))
1969
							unset($ifcfg['wireless'][$setting]);
1970
					}
1971
				}
1972
				if (!$sync_changes)
1973
					break;
1974
			}
1975
		}
1976
	}
1977

    
1978
	// Read or write settings at shared area
1979
	if (isset($config['wireless']['interfaces'][$baseif])) {
1980
		foreach ($shared_settings as $setting) {
1981
			if ($sync_changes) {
1982
				if (isset($ifcfg['wireless'][$setting]))
1983
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
1984
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
1985
					unset($config['wireless']['interfaces'][$baseif][$setting]);
1986
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
1987
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
1988
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
1989
				else if (isset($ifcfg['wireless'][$setting]))
1990
					unset($ifcfg['wireless'][$setting]);
1991
			}
1992
		}
1993
	}
1994

    
1995
	// Sync the mode on the clone creation page with the configured mode on the interface
1996
	if (interface_is_wireless_clone($ifcfg['if'])) {
1997
		foreach ($config['wireless']['clone'] as &$clone) {
1998
			if ($clone['cloneif'] == $ifcfg['if']) {
1999
				if ($sync_changes) {
2000
					$clone['mode'] = $ifcfg['wireless']['mode'];
2001
				} else {
2002
					$ifcfg['wireless']['mode'] = $clone['mode'];
2003
				}
2004
				break;
2005
			}
2006
		}
2007
		unset($clone);
2008
	}
2009
}
2010

    
2011
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2012
	global $config, $g;
2013

    
2014
	/*    open up a shell script that will be used to output the commands.
2015
	 *    since wireless is changing a lot, these series of commands are fragile
2016
     *    and will sometimes need to be verified by a operator by executing the command
2017
     *    and returning the output of the command to the developers for inspection.  please
2018
     *    do not change this routine from a shell script to individul exec commands.  -sullrich
2019
	 */
2020

    
2021
	// Remove script file
2022
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2023

    
2024
	// Clone wireless nic if needed.
2025
	interface_wireless_clone($if, $wl);
2026

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

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

    
2034
	/* set values for /path/program */
2035
	$hostapd = "/usr/sbin/hostapd";
2036
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2037
	$ifconfig = "/sbin/ifconfig";
2038
	$sysctl = "/sbin/sysctl";
2039
	$killall = "/usr/bin/killall";
2040

    
2041
	/* Set all wireless ifconfig variables (splitt up to get rid of needed checking) */
2042

    
2043
	$wlcmd = array();
2044
	$wl_sysctl = array();
2045
	/* Make sure it's up */
2046
	$wlcmd[] = "up";
2047
	/* Set a/b/g standard */
2048
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2049
	$wlcmd[] = "mode " . escapeshellarg($standard);
2050

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

    
2056
	/* Set ssid */
2057
	if($wlcfg['ssid'])
2058
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2059

    
2060
	/* Set 802.11g protection mode */
2061
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2062

    
2063
	/* set wireless channel value */
2064
	if(isset($wlcfg['channel'])) {
2065
		if($wlcfg['channel'] == "0") {
2066
			$wlcmd[] = "channel any";
2067
		} else {
2068
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2069
		}
2070
	}
2071

    
2072
	/* Set antenna diversity value */
2073
	if(isset($wlcfg['diversity']))
2074
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2075

    
2076
	/* Set txantenna value */
2077
	if(isset($wlcfg['txantenna']))
2078
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2079

    
2080
	/* Set rxantenna value */
2081
	if(isset($wlcfg['rxantenna']))
2082
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2083

    
2084
	/* set Distance value */
2085
	if($wlcfg['distance'])
2086
		$distance = escapeshellarg($wlcfg['distance']);
2087

    
2088
	/* Set wireless hostap mode */
2089
	if ($wlcfg['mode'] == "hostap") {
2090
		$wlcmd[] = "mediaopt hostap";
2091
	} else {
2092
		$wlcmd[] = "-mediaopt hostap";
2093
	}
2094

    
2095
	/* Set wireless adhoc mode */
2096
	if ($wlcfg['mode'] == "adhoc") {
2097
		$wlcmd[] = "mediaopt adhoc";
2098
	} else {
2099
		$wlcmd[] = "-mediaopt adhoc";
2100
	}
2101

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

    
2104
	/* handle hide ssid option */
2105
	if(isset($wlcfg['hidessid']['enable'])) {
2106
		$wlcmd[] = "hidessid";
2107
	} else {
2108
		$wlcmd[] = "-hidessid";
2109
	}
2110

    
2111
	/* handle pureg (802.11g) only option */
2112
	if(isset($wlcfg['pureg']['enable'])) {
2113
		$wlcmd[] = "mode 11g pureg";
2114
	} else {
2115
		$wlcmd[] = "-pureg";
2116
	}
2117

    
2118
	/* handle puren (802.11n) only option */
2119
	if(isset($wlcfg['puren']['enable'])) {
2120
		$wlcmd[] = "puren";
2121
	} else {
2122
		$wlcmd[] = "-puren";
2123
	}
2124

    
2125
	/* enable apbridge option */
2126
	if(isset($wlcfg['apbridge']['enable'])) {
2127
		$wlcmd[] = "apbridge";
2128
	} else {
2129
		$wlcmd[] = "-apbridge";
2130
	}
2131

    
2132
	/* handle turbo option */
2133
	if(isset($wlcfg['turbo']['enable'])) {
2134
		$wlcmd[] = "mediaopt turbo";
2135
	} else {
2136
		$wlcmd[] = "-mediaopt turbo";
2137
	}
2138

    
2139
	/* handle txpower setting */
2140
	/* if($wlcfg['txpower'] <> "")
2141
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2142
	*/
2143
	/* handle wme option */
2144
	if(isset($wlcfg['wme']['enable'])) {
2145
		$wlcmd[] = "wme";
2146
	} else {
2147
		$wlcmd[] = "-wme";
2148
	}
2149

    
2150
	/* set up wep if enabled */
2151
	$wepset = "";
2152
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2153
		switch($wlcfg['wpa']['auth_algs']) {
2154
			case "1":
2155
				$wepset .= "authmode open wepmode on ";
2156
				break;
2157
			case "2":
2158
				$wepset .= "authmode shared wepmode on ";
2159
				break;
2160
			case "3":
2161
				$wepset .= "authmode mixed wepmode on ";
2162
		}
2163
		$i = 1;
2164
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2165
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2166
			if (isset($wepkey['txkey'])) {
2167
				$wlcmd[] = "weptxkey {$i} ";
2168
			}
2169
			$i++;
2170
		}
2171
		$wlcmd[] = $wepset;
2172
	} else {
2173
		$wlcmd[] = "authmode open wepmode off ";
2174
	}
2175

    
2176
	mwexec(kill_hostapd("{$if}"));
2177
	mwexec(kill_wpasupplicant("{$if}"));
2178

    
2179
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2180
	conf_mount_rw();
2181

    
2182
	switch ($wlcfg['mode']) {
2183
		case 'bss':
2184
			if (isset($wlcfg['wpa']['enable'])) {
2185
				$wpa .= <<<EOD
2186
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2187
ctrl_interface_group=0
2188
ap_scan=1
2189
#fast_reauth=1
2190
network={
2191
ssid="{$wlcfg['ssid']}"
2192
scan_ssid=1
2193
priority=5
2194
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2195
psk="{$wlcfg['wpa']['passphrase']}"
2196
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2197
group={$wlcfg['wpa']['wpa_pairwise']}
2198
}
2199
EOD;
2200

    
2201
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2202
				fwrite($fd, "{$wpa}");
2203
				fclose($fd);
2204
			}
2205
			break;
2206
		case 'hostap':
2207
			if($wlcfg['wpa']['passphrase']) 
2208
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2209
			else 
2210
				$wpa_passphrase = "";
2211
			if (isset($wlcfg['wpa']['enable'])) {
2212
				$wpa .= <<<EOD
2213
interface={$if}
2214
driver=bsd
2215
logger_syslog=-1
2216
logger_syslog_level=0
2217
logger_stdout=-1
2218
logger_stdout_level=0
2219
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2220
ctrl_interface={$g['varrun_path']}/hostapd
2221
ctrl_interface_group=wheel
2222
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2223
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2224
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2225
ssid={$wlcfg['ssid']}
2226
debug={$wlcfg['wpa']['debug_mode']}
2227
auth_algs={$wlcfg['wpa']['auth_algs']}
2228
wpa={$wlcfg['wpa']['wpa_mode']}
2229
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2230
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2231
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2232
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2233
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2234
{$wpa_passphrase}
2235

    
2236
EOD;
2237

    
2238
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2239
	$wpa .= <<<EOD
2240
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2241
rsn_preauth=1
2242
rsn_preauth_interfaces={$if}
2243

    
2244
EOD;
2245

    
2246
}
2247
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2248
					$auth_server_port = "1812";
2249
					if($wlcfg['auth_server_port']) 
2250
						$auth_server_port = $wlcfg['auth_server_port'];
2251
					$wpa .= <<<EOD
2252

    
2253
ieee8021x=1
2254
auth_server_addr={$wlcfg['auth_server_addr']}
2255
auth_server_port={$auth_server_port}
2256
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2257

    
2258
EOD;
2259
				} else {
2260
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2261
				}
2262

    
2263
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2264
				fwrite($fd, "{$wpa}");
2265
				fclose($fd);
2266

    
2267
			}
2268
			break;
2269
	}
2270

    
2271
	/*
2272
	 *    all variables are set, lets start up everything
2273
	 */
2274

    
2275
	$baseif = interface_get_wireless_base($if);
2276
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2277
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2278

    
2279
	/* set sysctls for the wireless interface */
2280
	if (!empty($wl_sysctl)) {
2281
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2282
		foreach ($wl_sysctl as $wl_sysctl_line) {
2283
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2284
		}
2285
	}
2286

    
2287
	/* set ack timers according to users preference (if he/she has any) */
2288
	if($distance) {
2289
		fwrite($fd_set, "# Enable ATH distance settings\n");
2290
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2291
	}
2292

    
2293
	if (isset($wlcfg['wpa']['enable'])) {
2294
		if ($wlcfg['mode'] == "bss") {
2295
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2296
		}
2297
		if ($wlcfg['mode'] == "hostap") {
2298
			/* add line to script to restore old mac to make hostapd happy */
2299
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2300
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2301
				if (is_macaddr($if_oldmac))
2302
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2303
						" link " . escapeshellarg($if_oldmac) . "\n");
2304
			}
2305

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

    
2308
			/* add line to script to restore spoofed mac after running hostapd */
2309
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2310
				if ($wl['spoofmac'])
2311
					$if_curmac = $wl['spoofmac'];
2312
				else
2313
					$if_curmac = get_interface_mac($if);
2314
				if (is_macaddr($if_curmac))
2315
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2316
						" link " . escapeshellarg($if_curmac) . "\n");
2317
			}
2318
		}
2319
	}
2320

    
2321
	fclose($fd_set);
2322
	conf_mount_ro();
2323

    
2324
	/* Making sure regulatory settings have actually changed
2325
	 * before applying, because changing them requires bringing
2326
	 * down all wireless networks on the interface. */
2327
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2328
	$ifconfig_str = implode($output);
2329
	unset($output);
2330
	$reg_changing = false;
2331

    
2332
	/* special case for the debug country code */
2333
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2334
		$reg_changing = true;
2335
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2336
		$reg_changing = true;
2337
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2338
		$reg_changing = true;
2339
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2340
		$reg_changing = true;
2341
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2342
		$reg_changing = true;
2343

    
2344
	if ($reg_changing) {
2345
		/* set regulatory domain */
2346
		if($wlcfg['regdomain'])
2347
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2348

    
2349
		/* set country */
2350
		if($wlcfg['regcountry'])
2351
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2352

    
2353
		/* set location */
2354
		if($wlcfg['reglocation'])
2355
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2356

    
2357
		$wlregcmd_args = implode(" ", $wlregcmd);
2358

    
2359
		/* build a complete list of the wireless clones for this interface */
2360
		$clone_list = array();
2361
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2362
			$clone_list[] = interface_get_wireless_clone($baseif);
2363
		if (is_array($config['wireless']['clone'])) {
2364
			foreach ($config['wireless']['clone'] as $clone) {
2365
				if ($clone['if'] == $baseif)
2366
					$clone_list[] = $clone['cloneif'];
2367
			}
2368
		}
2369

    
2370
		/* find which clones are up and bring them down */
2371
		$clones_up = array();
2372
		foreach ($clone_list as $clone_if) {
2373
			$clone_status = pfSense_get_interface_addresses($clone_if);
2374
			if ($clone_status['status'] == 'up') {
2375
				$clones_up[] = $clone_if;
2376
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2377
			}
2378
		}
2379

    
2380
		/* apply the regulatory settings */
2381
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2382

    
2383
		/* bring the clones back up that were previously up */
2384
		foreach ($clones_up as $clone_if) {
2385
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2386

    
2387
			/*
2388
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2389
			 * is in infrastructure mode, and WPA is enabled.
2390
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2391
			 */
2392
			if ($clone_if != $if) {
2393
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2394
				if ( !empty($friendly_if)
2395
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2396
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2397
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2398
				}
2399
			}
2400
		}
2401
	}
2402

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

    
2407
	/* configure wireless */
2408
	$wlcmd_args = implode(" ", $wlcmd);
2409
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2410

    
2411
	
2412
	sleep(1);
2413
	/* execute hostapd and wpa_supplicant if required in shell */
2414
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2415

    
2416
	return 0;
2417

    
2418
}
2419

    
2420
function kill_hostapd($interface) {
2421
	return "/bin/pkill -f \"hostapd .*{$interface}\"\n";
2422
}
2423

    
2424
function kill_wpasupplicant($interface) {
2425
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\"\n";
2426
}
2427

    
2428
function find_dhclient_process($interface) {
2429
	if ($interface)
2430
		$pid = `/bin/pgrep -xf "dhclient: {$interface}"`;
2431
	else
2432
		$pid = 0;
2433

    
2434
	return $pid;
2435
}
2436

    
2437
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2438
	global $config, $g;
2439
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2440

    
2441
	$wancfg = $config['interfaces'][$interface];
2442

    
2443
	$realif = get_real_interface($interface);
2444
	$realhwif = interface_translate_type_to_real($interface);
2445

    
2446
	if (!$g['booting']) {
2447
		/* remove all IPv4 addresses */
2448
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0);
2449

    
2450
		switch ($wancfg['ipaddr']) {
2451
			case 'pppoe':
2452
			case 'l2tp':
2453
			case 'pptp':
2454
			case 'ppp':
2455
				interface_bring_down($interface, true);
2456
				break;
2457
			default:
2458
				interface_bring_down($interface);
2459
				break;
2460
		}
2461
	}
2462

    
2463
	/* wireless configuration? */
2464
	if (is_array($wancfg['wireless']))
2465
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2466

    
2467
	if ($wancfg['spoofmac']) {
2468
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2469
			" link " . escapeshellarg($wancfg['spoofmac']));
2470

    
2471
                /*
2472
                 * All vlans need to spoof their parent mac address, too.  see
2473
                 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2474
                 */
2475
                if (is_array($config['vlans']['vlan'])) {
2476
                        foreach ($config['vlans']['vlan'] as $vlan) {
2477
                                if ($vlan['if'] == $realhwif)
2478
                                        mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2479
                                                " link " . escapeshellarg($wancfg['spoofmac']));
2480
                        }
2481
                }
2482
	}  else {
2483
		$mac = get_interface_mac($realhwif);
2484
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2485
			/*   this is not a valid mac address.  generate a
2486
			 *   temporary mac address so the machine can get online.
2487
			 */
2488
			echo "Generating new MAC address.";
2489
			$random_mac = generate_random_mac_address();
2490
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2491
				" link " . escapeshellarg($random_mac));
2492
			$wancfg['spoofmac'] = $random_mac;
2493
			write_config();
2494
			file_notice("MAC Address altered", "The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface {$realif} has been automatically replaced with {$random_mac}", "Interfaces");
2495
		}
2496
	}
2497

    
2498
	/* media */
2499
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2500
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2501
		if ($wancfg['media'])
2502
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2503
		if ($wancfg['mediaopt'])
2504
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2505
		mwexec($cmd);
2506
	}
2507
	if (!empty($wancfg['mtu']))
2508
		pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2509

    
2510
	$options = pfSense_get_interface_addresses($realhwif);
2511
	if (is_array($options) && isset($options['caps']['polling'])) {
2512
		if (isset($config['system']['polling']))
2513
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2514
		else
2515
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2516
	}
2517

    
2518
	/* skip vlans for checksumming and polling */
2519
        if (!stristr($realhwif, "vlan") && is_array($options)) {
2520
		$flags = 0;
2521
		if(isset($config['system']['disablechecksumoffloading'])) {
2522
			if (isset($options['encaps']['txcsum']))
2523
				$flags |= IFCAP_TXCSUM;
2524
			if (isset($options['encaps']['rxcsum']))
2525
				$flags |= IFCAP_RXCSUM;
2526
        	} else {
2527
 			if (!isset($options['caps']['txcsum']))
2528
				$flags |= IFCAP_TXCSUM;
2529
			if (!isset($options['caps']['rxcsum']))
2530
				$flags |= IFCAP_RXCSUM;
2531
        	}
2532

    
2533
        	if(isset($config['system']['disablesegmentationoffloading'])) {
2534
                	if (isset($options['encaps']['tso4']))
2535
				$flags |= IFCAP_TSO;
2536
                	if (isset($options['encaps']['tso6']))
2537
				$flags |= IFCAP_TSO;
2538
        	} else {
2539
                	if (!isset($options['caps']['tso4']))
2540
				$flags |= IFCAP_TSO;
2541
                	if (!isset($options['caps']['tso6']))
2542
				$flags |= IFCAP_TSO;
2543
        	}
2544

    
2545
        	if(isset($config['system']['disablelargereceiveoffloading'])) {
2546
                	if (isset($options['encaps']['lro']))
2547
				$flags |= IFCAP_LRO;
2548
        	} else {
2549
                	if (!isset($options['caps']['lro']))
2550
				$flags |= IFCAP_LRO;
2551
        	}
2552

    
2553
        	/* if the NIC supports polling *AND* it is enabled in the GUI */
2554
        	if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2555
			$flags |= IFCAP_POLLING;
2556
		}
2557
               	pfSense_interface_capabilities($realhwif, -$flags);
2558
	}
2559

    
2560
	/* invalidate interface/ip/sn cache */
2561
	get_interface_arr(true);
2562
	unset($interface_ip_arr_cache[$realif]);
2563
	unset($interface_sn_arr_cache[$realif]);
2564

    
2565
	switch ($wancfg['ipaddr']) {
2566
		case 'carpdev-dhcp':
2567
			interface_carpdev_dhcp_configure($interface);
2568
			break;
2569
		case 'dhcp':
2570
			interface_dhcp_configure($interface);
2571
			break;
2572
		case 'pppoe':
2573
		case 'l2tp':
2574
		case 'pptp':
2575
		case 'ppp':
2576
			interface_ppps_configure($interface);
2577
			break;
2578
		default:
2579
			if ($wancfg['ipaddr'] <> "" && $wancfg['subnet'] <> "") {
2580
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2581
			} else if (substr($realif, 0, 3) == "gre") {
2582
				if (is_array($config['gres']['gre'])) {
2583
					foreach ($config['gres']['gre'] as $gre)
2584
						if ($gre['greif'] == $realif)
2585
							interface_gre_configure($gre);
2586
				}
2587
			} else if (substr($realif, 0, 3) == "gif") {
2588
				 if (is_array($config['gifs']['gif'])) {
2589
					foreach ($config['gifs']['gif'] as $gif)
2590
						if($gif['gifif'] == $interface)
2591
							interface_gif_configure($gif);
2592
				}
2593
			} else if (substr($realif, 0, 4) == "ovpn") {
2594
				/* XXX: Should be done anything?! */
2595
			}
2596
			break;
2597
	}
2598

    
2599
	if(does_interface_exist($wancfg['if']))
2600
		interfaces_bring_up($wancfg['if']);
2601

    
2602
	interface_netgraph_needed($interface);
2603
 	
2604
	if (!$g['booting']) {
2605
		link_interface_to_vips($interface, "update");
2606

    
2607
		unset($gre);
2608
		$gre = link_interface_to_gre($interface);
2609
		if (!empty($gre))
2610
			array_walk($gre, 'interface_gre_configure');
2611

    
2612
		unset($gif);
2613
		$gif = link_interface_to_gif($interface);
2614
		if (!empty($gif))
2615
                       	array_walk($gif, 'interface_gif_configure');
2616

    
2617
		if ($linkupevent == false) {
2618
			unset($bridgetmp);
2619
			$bridgetmp = link_interface_to_bridge($interface);
2620
			if (!empty($bridgetmp))
2621
				interface_bridge_add_member($bridgetmp, $realif);
2622
		}
2623

    
2624
		$grouptmp = link_interface_to_group($interface);
2625
		if (!empty($grouptmp))
2626
			array_walk($grouptmp, 'interface_group_add_member');
2627

    
2628
		if ($interface == "lan")
2629
			/* make new hosts file */
2630
			system_hosts_generate();
2631

    
2632
		if ($reloadall == true) {
2633

    
2634
			/* reconfigure static routes (kernel may have deleted them) */
2635
			system_routing_configure($interface);
2636

    
2637
			/* reload ipsec tunnels */
2638
			vpn_ipsec_configure();
2639

    
2640
			/* restart dnsmasq */
2641
			services_dnsmasq_configure();
2642

    
2643
			/* update dyndns */
2644
			send_event("service reload dyndns {$interface}");
2645

    
2646
			/* reload captive portal */
2647
			captiveportal_init_rules();
2648
		}
2649
	}
2650

    
2651
	return 0;
2652
}
2653

    
2654
function interface_carpdev_dhcp_configure($interface = "wan") {
2655
	global $config, $g;
2656

    
2657
	$wancfg = $config['interfaces'][$interface];
2658
	$wanif = $wancfg['if'];
2659
	/* bring wan interface up before starting dhclient */
2660
	if($wanif)
2661
		interfaces_bring_up($wanif);
2662
	else 
2663
		log_error("Could not bring wanif up in terface_carpdev_dhcp_configure()");
2664

    
2665
	return 0;
2666
}
2667

    
2668
function interface_dhcp_configure($interface = "wan") {
2669
	global $config, $g;
2670

    
2671
	$wancfg = $config['interfaces'][$interface];
2672
	if (empty($wancfg))
2673
		$wancfg = array();
2674

    
2675
	/* generate dhclient_wan.conf */
2676
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
2677
	if (!$fd) {
2678
		printf("Error: cannot open dhclient_{$interface}.conf in interfaces_wan_dhcp_configure() for writing.\n");
2679
		return 1;
2680
	}
2681

    
2682
	if ($wancfg['dhcphostname']) {
2683
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
2684
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
2685
	} else {
2686
		$dhclientconf_hostname = "";
2687
	}
2688

    
2689
	$wanif = get_real_interface($interface);
2690
	if (empty($wanif)) {
2691
		log_error("Invalid interface \"{$interface}\" in interface_dhcp_configure()");
2692
		return 0;
2693
	}
2694
 	$dhclientconf = "";
2695
	
2696
	$dhclientconf .= <<<EOD
2697
interface "{$wanif}" {
2698
timeout 60;
2699
retry 1;
2700
select-timeout 0;
2701
initial-interval 1;
2702
	{$dhclientconf_hostname}
2703
	script "/sbin/dhclient-script";
2704
}
2705

    
2706
EOD;
2707

    
2708
if(is_ipaddr($wancfg['alias-address'])) {
2709
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
2710
	$dhclientconf .= <<<EOD
2711
alias {
2712
	interface  "{$wanif}";
2713
	fixed-address {$wancfg['alias-address']};
2714
	option subnet-mask {$subnetmask};
2715
}
2716

    
2717
EOD;
2718
}
2719
	fwrite($fd, $dhclientconf);
2720
	fclose($fd);
2721

    
2722
	/* bring wan interface up before starting dhclient */
2723
	if($wanif)
2724
		interfaces_bring_up($wanif);
2725
	else 
2726
		log_error("Could not bring up {$wanif} interface in interface_dhcp_configure()");
2727

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

    
2731
	return 0;
2732
}
2733

    
2734
function interfaces_group_setup() {
2735
	global $config;
2736

    
2737
	if (!is_array($config['ifgroups']['ifgroupentry']))
2738
		return;
2739

    
2740
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
2741
		interface_group_setup($groupar);
2742

    
2743
	return;
2744
}
2745

    
2746
function interface_group_setup(&$groupname /* The parameter is an array */) {
2747
	global $config;
2748

    
2749
	if (!is_array($groupname))
2750
		return;
2751
	$members = explode(" ", $groupname['members']);
2752
	foreach($members as $ifs) {
2753
		$realif = get_real_interface($ifs);
2754
		if ($realif)
2755
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
2756
	}
2757

    
2758
	return;
2759
}
2760

    
2761
function interface_group_add_member($interface, $groupname) {
2762
	$interface = get_real_interface($interface);
2763
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
2764
}
2765
 
2766
/* COMPAT Function */
2767
function convert_friendly_interface_to_real_interface_name($interface) {
2768
	return get_real_interface($interface);
2769
}
2770

    
2771
/* COMPAT Function */
2772
function get_real_wan_interface($interface = "wan") {
2773
	return get_real_interface($interface);
2774
}
2775

    
2776
/* COMPAT Function */
2777
function get_current_wan_address($interface = "wan") {
2778
	return get_interface_ip($interface);
2779
}
2780

    
2781
/*
2782
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
2783
 */
2784
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
2785
        global $config;
2786

    
2787
	if (stristr($interface, "vip")) {
2788
                $index = intval(substr($interface, 3));
2789
                foreach ($config['virtualip']['vip'] as $counter => $vip) {
2790
                        if ($vip['mode'] == "carpdev-dhcp" || $vip['mode'] == "carp")  {
2791
                                if ($index == $vip['vhid'])
2792
                                        return $vip['interface'];
2793
                        }
2794
                }
2795
        }
2796

    
2797
        /* XXX: For speed reasons reference directly the interface array */
2798
	$ifdescrs = &$config['interfaces'];
2799
        //$ifdescrs = get_configured_interface_list(false, true);
2800

    
2801
        foreach ($ifdescrs as $if => $ifname) {
2802
                if ($config['interfaces'][$if]['if'] == $interface)
2803
                        return $if;
2804

    
2805
                if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
2806
                        return $if;
2807

    
2808
                $int = interface_translate_type_to_real($if);
2809
                if ($int == $interface)
2810
                        return $ifname;
2811
        }
2812
        return NULL;
2813
}
2814

    
2815
/* attempt to resolve interface to friendly descr */
2816
function convert_friendly_interface_to_friendly_descr($interface) {
2817
        global $config;
2818

    
2819
        switch ($interface) {
2820
        case "l2tp":
2821
        	$ifdesc = "L2TP";
2822
                break;
2823
	case "pptp":
2824
		$ifdesc = "PPTP";
2825
		break;
2826
	case "pppoe":
2827
		$ifdesc = "PPPoE";
2828
		break;
2829
	case "openvpn":
2830
		$ifdesc = "OpenVPN";
2831
		break;
2832
	case "enc0":
2833
	case "ipsec":
2834
		$ifdesc = "IPsec";
2835
		break;
2836
        default:
2837
                if (isset($config['interfaces'][$interface])) {
2838
                        if (empty($config['interfaces'][$interface]['descr']))
2839
                                $ifdesc = strtoupper($interface);
2840
                        else
2841
                                $ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
2842
			break;
2843
		} else if (substr($interface, 0, 3) == "vip") {
2844
			if (is_array($config['virtualip']['vip'])) {
2845
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
2846
					if ($vip['mode'] == "carpdev-dhcp" || $vip['mode'] == "carp")  {
2847
						if ($interface == "vip{$vip['vhid']}")
2848
							return "{$vip['subnet']} - {$vip['descr']}";
2849
					}
2850
				}
2851
                        }
2852
                } else {
2853
			/* if list */
2854
			$ifdescrs = get_configured_interface_with_descr(false, true);
2855
			foreach ($ifdescrs as $if => $ifname) {
2856
					if ($if == $interface || $ifname == $interface)
2857
						return $ifname;
2858
			}
2859
		}
2860
                break;
2861
        }
2862

    
2863
        return $ifdesc;
2864
}
2865

    
2866
function convert_real_interface_to_friendly_descr($interface) {
2867
        global $config;
2868

    
2869
        $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
2870

    
2871
        if ($ifdesc) {
2872
                $iflist = get_configured_interface_with_descr(false, true);
2873
                return $iflist[$ifdesc];
2874
        }
2875

    
2876
        return $interface;
2877
}
2878

    
2879
/*
2880
 *  interface_translate_type_to_real($interface):
2881
 *              returns the real hardware interface name for a friendly interface.  ie: wan
2882
 */
2883
function interface_translate_type_to_real($interface) {
2884
        global $config;
2885

    
2886
	if (empty($config['interfaces'][$interface]))
2887
		return $interface;
2888
	$tmpif = $config['interfaces'][$interface];
2889
	switch ($tmpif['type']) {
2890
	case "ppp":
2891
	case "pppoe":
2892
	case "pptp":
2893
	case "l2tp":
2894
		if (is_array($config['ppps']['ppp'])) {
2895
			foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
2896
				if ($tmpif['if'] == $ppp['if']) {
2897
					$interface = $ppp['ports'];
2898
					break;
2899
				}
2900
			}
2901
		}
2902
		break;
2903
	case "dhcp":
2904
	case "static":
2905
	default:
2906
		$interface = $tmpif['if'];
2907
		break;
2908
	}
2909

    
2910
	return $interface;
2911
}
2912

    
2913
function interface_is_wireless_clone($wlif) {
2914
	if(!stristr($wlif, "_wlan")) {
2915
		return false;
2916
	} else {
2917
		return true;
2918
	}
2919
}
2920

    
2921
function interface_get_wireless_base($wlif) {
2922
	if(!stristr($wlif, "_wlan")) {
2923
		return $wlif;
2924
	} else {
2925
		return substr($wlif, 0, stripos($wlif, "_wlan"));
2926
	}
2927
}
2928

    
2929
function interface_get_wireless_clone($wlif) {
2930
	if(!stristr($wlif, "_wlan")) {
2931
		return $wlif . "_wlan0";
2932
	} else {
2933
		return $wlif;
2934
	}
2935
}
2936

    
2937
function get_real_interface($interface = "wan") {
2938
    global $config;
2939

    
2940
	$wanif = NULL;
2941

    
2942
	switch ($interface) {
2943
	case "l2tp":
2944
		$wanif = "l2tp";
2945
		break;
2946
	case "pptp":
2947
		$wanif = "pptp";
2948
		break;
2949
	case "pppoe":
2950
		$wanif = "pppoe";
2951
		break;
2952
	case "openvpn":
2953
		$wanif = "openvpn";
2954
		break;
2955
	case "ipsec":
2956
	case "enc0":
2957
		$wanif = "enc0";
2958
		break;
2959
	case "ppp":
2960
		$wanif = "ppp";
2961
		break;
2962
	default:
2963
		// If a real interface was alread passed simply
2964
		// pass the real interface back.  This encourages
2965
		// the usage of this function in more cases so that
2966
		// we can combine logic for more flexibility.
2967
		if(does_interface_exist($interface)) {
2968
			$wanif = $interface;
2969
			break;
2970
		}
2971
		if (empty($config['interfaces'][$interface]))
2972
			break;
2973

    
2974
		$cfg = &$config['interfaces'][$interface];
2975

    
2976
		// Wireless cloned NIC support (FreeBSD 8+)
2977
		// interface name format: $parentnic_wlanparentnic#
2978
		// example: ath0_wlan0
2979
		if (is_interface_wireless($cfg['if'])) {
2980
			$wanif = interface_get_wireless_clone($cfg['if']);
2981
			break;
2982
		}
2983
		/*
2984
		if (empty($cfg['if'])) {
2985
			$wancfg = $cfg['if'];
2986
			break;
2987
		}
2988
		*/
2989

    
2990
		switch ($cfg['ipaddr']) {
2991
			case "carpdev-dhcp":
2992
				$viparr = &$config['virtualip']['vip'];
2993
				if(is_array($viparr))
2994
				foreach ($viparr as $counter => $vip) {
2995
					if ($vip['mode'] == "carpdev-dhcp") {
2996
						if($vip['interface'] == $interface) {
2997
							$wanif = "carp{$counter}";
2998
							break;
2999
						}
3000
					}
3001
				}
3002
				break;
3003
			case "pppoe": 
3004
			case "pptp": 
3005
			case "l2tp": 
3006
			case "ppp":
3007
				$wanif = $cfg['if'];
3008
				break;
3009
			default:
3010
				$wanif = $cfg['if'];
3011
				break;
3012
		}
3013
		break;
3014
	}
3015

    
3016
    return $wanif;
3017
}
3018

    
3019
/* Guess the physical interface by providing a IP address */
3020
function guess_interface_from_ip($ipaddress) {
3021
	if(! is_ipaddr($ipaddress)) {
3022
		return false;
3023
	}
3024
	/* create a route table we can search */
3025
	exec("netstat -rnWf inet", $output, $ret);
3026
	foreach($output as $line) {
3027
		if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
3028
			$fields = preg_split("/[ ]+/", $line);
3029
			if(ip_in_subnet($ipaddress, $fields[0])) {
3030
				return $fields[6];
3031
			}
3032
		}
3033
	}
3034
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
3035
	if(empty($ret)) {
3036
        	return false;
3037
	}
3038
	return $ret;
3039
}
3040

    
3041
/*
3042
 * find_ip_interface($ip): return the interface where an ip is defined
3043
 */
3044
function find_ip_interface($ip)
3045
{
3046
        /* if list */
3047
        $ifdescrs = get_configured_interface_list();
3048

    
3049
        foreach ($ifdescrs as $ifdescr => $ifname) {
3050
		if ($ip == get_interface_ip($ifname)) {
3051
                	$int = get_real_interface($ifname);
3052
			return $int;
3053
		}
3054
        }
3055
        return false;
3056
}
3057

    
3058
/*
3059
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
3060
 */
3061
function find_number_of_created_carp_interfaces() {
3062
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
3063
}
3064

    
3065
function get_all_carp_interfaces() {
3066
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
3067
	$ints = explode(" ", $ints);
3068
	return $ints;
3069
}
3070

    
3071
/*
3072
 * find_carp_interface($ip): return the carp interface where an ip is defined
3073
 */
3074
function find_carp_interface($ip) {
3075
	global $config;
3076
	if (is_array($config['virtualip']['vip'])) {
3077
		foreach ($config['virtualip']['vip'] as $vip) {
3078
			if ($vip['mode'] == "carp" || $vip['mode'] == "carpdev") {
3079
				$carp_ip = get_interface_ip($vip['interface']);
3080
				$if = `ifconfig | grep '$ip ' -B1 | head -n1 | cut -d: -f1`;
3081
				if ($if)
3082
					return $if;
3083
			}
3084
		}
3085
	}
3086
}
3087

    
3088
function link_carp_interface_to_parent($interface) {
3089
        global $config;
3090

    
3091
        if ($interface == "")
3092
                return;
3093

    
3094
        $carp_ip = get_interface_ip($interface);
3095
        if (!is_ipaddr($carp_ip))
3096
                return;
3097

    
3098
        /* if list */
3099
        $ifdescrs = get_configured_interface_list();
3100
        foreach ($ifdescrs as $ifdescr => $ifname) {
3101
                $interfaceip = get_interface_ip($ifname);
3102
                $subnet_bits = get_interface_subnet($ifname);
3103
                $subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3104
                if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3105
                        return $ifname;
3106
        }
3107

    
3108
        return "";
3109
}
3110

    
3111
/****f* interfaces/link_ip_to_carp_interface
3112
 * NAME
3113
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3114
 * INPUTS
3115
 *   $ip
3116
 * RESULT
3117
 *   $carp_ints
3118
 ******/
3119
function link_ip_to_carp_interface($ip) {
3120
        global $config;
3121

    
3122
        if (!is_ipaddr($ip))
3123
                return;
3124

    
3125
        $carp_ints = "";
3126
        if (is_array($config['virtualip']['vip'])) {
3127
		$first = 0;
3128
		$carp_int = array();
3129
                foreach ($config['virtualip']['vip'] as $vip) {
3130
                        if ($vip['mode'] == "carp" || $vip['mode'] == "carpdev") {
3131
                                $carp_ip = $vip['subnet'];
3132
                                $carp_sn = $vip['subnet_bits'];
3133
                                $carp_nw = gen_subnet($carp_ip, $carp_sn);
3134
                                if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}"))
3135
					$carp_int[] = "vip{$vip['vhid']}";
3136
                        }
3137
                }
3138
		if (!empty($carp_int))
3139
			$carp_ints = implode(" ", array_unique($carp_int));
3140
        }
3141

    
3142
        return $carp_ints;
3143
}
3144

    
3145
function link_interface_to_vlans($int, $action = "") {
3146
	global $config;
3147

    
3148
	if (empty($int))
3149
		return;
3150

    
3151
	if (is_array($config['vlans']['vlan'])) {
3152
                foreach ($config['vlans']['vlan'] as $vlan) {
3153
			if ($int == $vlan['if']) {
3154
				if ($action == "update") {
3155
					interfaces_bring_up($int);
3156
				} else if ($action == "")
3157
					return $vlan;
3158
			}
3159
		}
3160
	}
3161
}
3162

    
3163
function link_interface_to_vips($int, $action = "") {
3164
        global $config;
3165

    
3166
        if (is_array($config['virtualip']['vip'])) {
3167
		foreach ($config['virtualip']['vip'] as $vip) {
3168
			if ($int == $vip['interface']) {
3169
				if ($action == "update") {
3170
					interface_vip_bring_down($vip);
3171
					interfaces_vips_configure($int);
3172
				} else
3173
					return $vip;
3174
			}
3175
		}
3176
	}
3177
}
3178

    
3179
/****f* interfaces/link_interface_to_bridge
3180
 * NAME
3181
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3182
 * INPUTS
3183
 *   $ip
3184
 * RESULT
3185
 *   bridge[0-99]
3186
 ******/
3187
function link_interface_to_bridge($int) {
3188
        global $config;
3189

    
3190
        if (is_array($config['bridges']['bridged'])) {
3191
                foreach ($config['bridges']['bridged'] as $bridge) {
3192
			if (in_array($int, explode(',', $bridge['members'])))
3193
                                return "{$bridge['bridgeif']}";
3194
		}
3195
	}
3196
}
3197

    
3198
function link_interface_to_group($int) {
3199
        global $config;
3200

    
3201
	$result = array();
3202

    
3203
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3204
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3205
			if (in_array($int, explode(" ", $group['members'])))
3206
				$result[$group['ifname']] = $int;
3207
		}
3208
	}
3209

    
3210
	return $result;
3211
}
3212

    
3213
function link_interface_to_gre($interface) {
3214
        global $config;
3215

    
3216
	$result = array();
3217

    
3218
        if (is_array($config['gres']['gre'])) {
3219
                foreach ($config['gres']['gre'] as $gre)
3220
                        if($gre['if'] == $interface)
3221
				$result[] = $gre;
3222
	}
3223

    
3224
	return $result;
3225
}
3226

    
3227
function link_interface_to_gif($interface) {
3228
        global $config;
3229

    
3230
	$result = array();
3231

    
3232
        if (is_array($config['gifs']['gif'])) {
3233
                foreach ($config['gifs']['gif'] as $gif)
3234
                        if($gif['if'] == $interface)
3235
                                $result[] = $gif;
3236
	}
3237

    
3238
	return $result;
3239
}
3240

    
3241
/*
3242
 * find_interface_ip($interface): return the interface ip (first found)
3243
 */
3244
function find_interface_ip($interface, $flush = false)
3245
{
3246
	global $interface_ip_arr_cache;
3247
	global $interface_sn_arr_cache;
3248

    
3249
	$interface = str_replace("\n", "", $interface);
3250
	
3251
	if (!does_interface_exist($interface))
3252
		return;
3253

    
3254
	/* Setup IP cache */
3255
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
3256
		$ifinfo = pfSense_get_interface_addresses($interface);
3257
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
3258
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
3259
	}
3260

    
3261
	return $interface_ip_arr_cache[$interface];
3262
}
3263

    
3264
function find_interface_subnet($interface, $flush = false)
3265
{
3266
	global $interface_sn_arr_cache;
3267
	global $interface_ip_arr_cache;
3268

    
3269
	$interface = str_replace("\n", "", $interface);
3270
	if (does_interface_exist($interface) == false)
3271
		return;
3272

    
3273
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
3274
		$ifinfo = pfSense_get_interface_addresses($interface);
3275
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
3276
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
3277
        }
3278

    
3279
	return $interface_sn_arr_cache[$interface];
3280
}
3281

    
3282
function ip_in_interface_alias_subnet($interface, $ipalias) {
3283
	global $config;
3284

    
3285
	if (empty($interface) || !is_ipaddr($ipalias))
3286
		return false;
3287
	if (is_array($config['virtualip']['vip'])) {
3288
                foreach ($config['virtualip']['vip'] as $vip) {
3289
                        switch ($vip['mode']) {
3290
                        case "ipalias":
3291
                                if ($vip['interface'] <> $interface)
3292
                                        break;
3293
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
3294
					return true;
3295
                                break;
3296
                        }
3297
                }
3298
	}
3299

    
3300
	return false;
3301
}
3302

    
3303
function get_interface_ip($interface = "wan")
3304
{
3305
	$realif = get_real_interface($interface);
3306
	if (!$realif) {
3307
		if (preg_match("/^carp/i", $interface))
3308
			$realif = $interface;
3309
		else if (preg_match("/^vip/i", $interface))
3310
			$realif = $interface;
3311
		else
3312
			return null;
3313
	}
3314

    
3315
	$curip = find_interface_ip($realif);
3316
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
3317
		return $curip;
3318
	else
3319
		return null;
3320
}
3321

    
3322
function get_interface_subnet($interface = "wan")
3323
{
3324
	$realif = get_real_interface($interface);
3325
	if (!$realif) {
3326
                if (preg_match("/^carp/i", $interface))
3327
                        $realif = $interface;
3328
                else if (preg_match("/^vip/i", $interface))
3329
                        $realif = $interface;
3330
                else
3331
                        return null;
3332
        }
3333

    
3334
	$cursn = find_interface_subnet($realif);
3335
	if (!empty($cursn))
3336
		return $cursn;
3337

    
3338
	return null;
3339
}
3340

    
3341
/* return outside interfaces with a gateway */
3342
function get_interfaces_with_gateway() {
3343
	global $config;
3344

    
3345
	$ints = array();
3346

    
3347
	/* loop interfaces, check config for outbound */
3348
	foreach($config['interfaces'] as $ifdescr => $ifname) {
3349
		switch ($ifname['ipaddr']) {
3350
			case "dhcp":
3351
			case "carpdev-dhcp":
3352
			case "ppp";
3353
			case "pppoe":
3354
			case "pptp":
3355
			case "l2tp":
3356
			case "ppp";
3357
				$ints[$ifdescr] = $ifdescr;
3358
			break;
3359
			default:
3360
				if (substr($ifname['if'], 0, 5) ==  "ovpnc" ||
3361
				    !empty($ifname['gateway']))
3362
					$ints[$ifdescr] = $ifdescr;
3363
			break;
3364
		}
3365
	}
3366
	return $ints;
3367
}
3368

    
3369
/* return true if interface has a gateway */
3370
function interface_has_gateway($friendly) {
3371
	global $config;
3372

    
3373
	if (!empty($config['interfaces'][$friendly])) {
3374
		$ifname = &$config['interfaces'][$friendly];
3375
		switch ($ifname['ipaddr']) {
3376
			case "dhcp":
3377
			case "carpdev-dhcp":
3378
			case "pppoe":
3379
			case "pptp":
3380
			case "l2tp":
3381
			case "ppp";
3382
				return true;
3383
			break;
3384
			default:
3385
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
3386
					return true;
3387
				if (!empty($ifname['gateway']))
3388
					return true;
3389
			break;
3390
		}
3391
	}
3392

    
3393
	return false;
3394
}
3395

    
3396
/****f* interfaces/is_altq_capable
3397
 * NAME
3398
 *   is_altq_capable - Test if interface is capable of using ALTQ
3399
 * INPUTS
3400
 *   $int            - string containing interface name
3401
 * RESULT
3402
 *   boolean         - true or false
3403
 ******/
3404

    
3405
function is_altq_capable($int) {
3406
        /* Per:
3407
         * http://www.freebsd.org/cgi/man.cgi?query=altq&manpath=FreeBSD+7.2-current&format=html
3408
         * Only the following drivers have ALTQ support
3409
         */
3410
	$capable = array("age", "ale", "an", "ath", "aue", "awi", "bce",
3411
			"bfe", "bge", "dc", "de", "ed", "em", "ep", "fxp", "gem",
3412
			"hme", "igb", "ipw", "iwi", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
3413
			"npe", "nve", "ral", "re", "rl", "rum", "run", "bwn", "sf", "sis", "sk",
3414
			"ste", "stge", "txp", "udav", "ural", "vge", "vr", "wi", "xl",
3415
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
3416
			"l2tp", "ppp");
3417

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

    
3420
        if (in_array($int_family[0], $capable))
3421
                return true;
3422
	else if (stristr($int, "vlan")) /* VLANs are name $parent_$vlan now */
3423
		return true;
3424
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
3425
		return true;
3426
        else
3427
                return false;
3428
}
3429

    
3430
/****f* interfaces/is_interface_wireless
3431
 * NAME
3432
 *   is_interface_wireless - Returns if an interface is wireless
3433
 * RESULT
3434
 *   $tmp       - Returns if an interface is wireless
3435
 ******/
3436
function is_interface_wireless($interface) {
3437
        global $config, $g;
3438

    
3439
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
3440
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
3441
                if (preg_match($g['wireless_regex'], $interface)) {
3442
                        if (isset($config['interfaces'][$friendly]))
3443
                                $config['interfaces'][$friendly]['wireless'] = array();
3444
                        return true;
3445
                }
3446
                return false;
3447
        } else
3448
                return true;
3449
}
3450

    
3451
function get_wireless_modes($interface) {
3452
	/* return wireless modes and channels */
3453
	$wireless_modes = array();
3454

    
3455
	$wlif = interface_translate_type_to_real($interface);
3456

    
3457
	if(is_interface_wireless($wlif)) {
3458
		$cloned_interface = get_real_interface($interface);
3459
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
3460
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
3461
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
3462

    
3463
		$interface_channels = "";
3464
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
3465
		$interface_channel_count = count($interface_channels);
3466

    
3467
		$c = 0;
3468
		while ($c < $interface_channel_count)
3469
		{
3470
			$channel_line = explode(",", $interface_channels["$c"]);
3471
			$wireless_mode = trim($channel_line[0]);
3472
			$wireless_channel = trim($channel_line[1]);
3473
			if(trim($wireless_mode) != "") {
3474
				/* if we only have 11g also set 11b channels */
3475
				if($wireless_mode == "11g") {
3476
					if(!isset($wireless_modes["11b"]))
3477
						$wireless_modes["11b"] = array();
3478
				} else if($wireless_mode == "11g ht") {
3479
					if(!isset($wireless_modes["11b"]))
3480
						$wireless_modes["11b"] = array();
3481
					if(!isset($wireless_modes["11g"]))
3482
						$wireless_modes["11g"] = array();
3483
					$wireless_mode = "11ng";
3484
				} else if($wireless_mode == "11a ht") {
3485
					if(!isset($wireless_modes["11a"]))
3486
						$wireless_modes["11a"] = array();
3487
					$wireless_mode = "11na";
3488
				}
3489
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
3490
			}
3491
			$c++;
3492
		}
3493
	}
3494
	return($wireless_modes);
3495
}
3496

    
3497
/* return channel numbers, frequency, max txpower, and max regulation txpower */
3498
function get_wireless_channel_info($interface) {
3499
	$wireless_channels = array();
3500

    
3501
	$wlif = interface_translate_type_to_real($interface);
3502

    
3503
	if(is_interface_wireless($wlif)) {
3504
		$cloned_interface = get_real_interface($interface);
3505
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
3506
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
3507
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
3508

    
3509
		$interface_channels = "";
3510
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
3511

    
3512
		foreach ($interface_channels as $channel_line) {
3513
			$channel_line = explode(",", $channel_line);
3514
			if(!isset($wireless_channels[$channel_line[0]]))
3515
				$wireless_channels[$channel_line[0]] = $channel_line;
3516
		}
3517
	}
3518
	return($wireless_channels);
3519
}
3520

    
3521
/****f* interfaces/get_interface_mtu
3522
 * NAME
3523
 *   get_interface_mtu - Return the mtu of an interface
3524
 * RESULT
3525
 *   $tmp       - Returns the mtu of an interface
3526
 ******/
3527
function get_interface_mtu($interface) {
3528
        $mtu = pfSense_get_interface_addresses($interface);
3529
        return $mtu['mtu'];
3530
}
3531

    
3532
function get_interface_mac($interface) {
3533

    
3534
	$macinfo = pfSense_get_interface_addresses($interface);
3535
	return $macinfo["macaddr"];
3536
}
3537

    
3538
/****f* pfsense-utils/generate_random_mac_address
3539
 * NAME
3540
 *   generate_random_mac - generates a random mac address
3541
 * INPUTS
3542
 *   none
3543
 * RESULT
3544
 *   $mac - a random mac address
3545
 ******/
3546
function generate_random_mac_address() {
3547
        $mac = "02";
3548
        for($x=0; $x<5; $x++)
3549
                $mac .= ":" . dechex(rand(16, 255));
3550
        return $mac;
3551
}
3552

    
3553
/****f* interfaces/is_jumbo_capable
3554
 * NAME
3555
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
3556
 * INPUTS
3557
 *   $int             - string containing interface name
3558
 * RESULT
3559
 *   boolean          - true or false
3560
 ******/
3561
function is_jumbo_capable($int) {
3562
        global $g;
3563

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

    
3566
        if (in_array($int_family[0], $g['vlan_long_frame']))
3567
                return true;
3568
        else
3569
                return false;
3570
}
3571

    
3572
function setup_pppoe_reset_file($pppif, $iface="") {
3573
	global $g;
3574
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
3575

    
3576
	if(!empty($iface) && !empty($pppif)){
3577
		$cron_cmd = <<<EOD
3578
#!/bin/sh
3579
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
3580
/usr/bin/logger -t pppoe{$iface} "PPPoE periodic reset executed on {$iface}"
3581

    
3582
EOD;
3583

    
3584
		file_put_contents($cron_file, $cron_cmd);
3585
		chmod($cron_file, 0700);
3586
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
3587
	} else
3588
		unlink_if_exists($cron_file);
3589
}
3590

    
3591
function get_vip_descr($ipaddress) {
3592
	global $config;
3593

    
3594
	foreach ($config['virtualip']['vip'] as $vip) {
3595
		if ($vip['subnet'] == $ipaddress) {
3596
			return ($vip['descr']);
3597
		}
3598
	}
3599
	return "";
3600
}
3601

    
3602
?>
(22-22/54)