Project

General

Profile

Download (104 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:	/usr/sbin/pppd	/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 interfaces_loopback_configure() {
88
	if($g['booting'])
89
		echo "Configuring loopback interface...";
90
	pfSense_interface_setaddress("lo0", "127.0.0.1");
91
	interfaces_bring_up("lo0");
92
	if($g['booting'])
93
		echo "done.\n";
94
	return 0;
95
}
96

    
97
function interfaces_vlan_configure() {
98
	global $config, $g;
99
	if($g['booting'])
100
		echo "Configuring VLAN interfaces...";
101
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
102
		foreach ($config['vlans']['vlan'] as $vlan) {
103
			if(empty($vlan['vlanif']))
104
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
105
			/* XXX: Maybe we should report any errors?! */
106
			interface_vlan_configure($vlan);
107
		}
108
	}
109
	if($g['booting'])
110
		echo "done.\n";
111
}
112

    
113
function interface_vlan_configure(&$vlan) {
114
        global $config, $g;
115

    
116
	if (!is_array($vlan)) {
117
		log_error("VLAN: called with wrong options. Problems with config!");
118
		return;
119
	}
120
	$if = $vlan['if'];
121
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
122
	$tag = $vlan['tag'];
123

    
124
	if (empty($if)) {
125
		log_error("interface_vlan_confgure called with if undefined.");
126
		return;
127
	}
128

    
129
	/* make sure the parent interface is up */
130
	interfaces_bring_up($if);
131
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
132
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
133

    
134
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
135
		interface_bring_down($vlanif, true);
136
	} else {
137
		$tmpvlanif = pfSense_interface_create("vlan");
138
		pfSense_interface_rename($tmpvlanif, $vlanif);
139
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
140
	}
141

    
142
	pfSense_vlan_create($vlanif, $if, $tag);
143

    
144
	interfaces_bring_up($vlanif);
145

    
146
	/* invalidate interface cache */
147
	get_interface_arr(true);
148

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

    
152
	return $vlanif;
153
}
154

    
155
function interface_qinq_configure(&$vlan, $fd = NULL) {
156
        global $config, $g;
157

    
158
        if (!is_array($vlan)) {
159
                log_error("QinQ compat VLAN: called with wrong options. Problems with config!\n");
160
                return;
161
        }
162

    
163
        $qinqif = $vlan['if'];
164
        $tag = $vlan['tag'];
165
        if(empty($qinqif)) {
166
                log_error("interface_qinq_confgure called with if undefined.\n");
167
                return;
168
        }
169
	$vlanif = interface_vlan_configure($vlan);
170

    
171
        if ($fd == NULL) {
172
                $exec = true;
173
                $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
174
        } else
175
                $exec = false;
176
        /* make sure the parent is converted to ng_vlan(4) and is up */
177
        interfaces_bring_up($qinqif);
178

    
179
        if (!empty($vlanif) && does_interface_exist($vlanif)) {
180
                fwrite($fd, "shutdown {$qinqif}qinq:\n");
181
                exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
182
                if (empty($result)) {
183
                        fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
184
                        fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
185
                        fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
186
                }
187
        } else {
188
                fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
189
                fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
190
                fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
191
        }
192

    
193
        /* invalidate interface cache */
194
        get_interface_arr(true);
195

    
196
        if (!stristr($qinqif, "vlan"))
197
                mwexec("/sbin/ifconfig {$qinqif} promisc\n");
198

    
199
        $macaddr = get_interface_mac($qinqif);
200
        if (!empty($vlan['members'])) {
201
                $members = explode(" ", $vlan['members']);
202
                foreach ($members as $qtag) {
203
                        $qinq = array();
204
                        $qinq['tag'] = $qtag;
205
                        $qinq['if'] = $vlanif;
206
                        interface_qinq2_configure($qinq, $fd, $macaddr);
207
                }
208
        }
209
        if ($exec == true) {
210
                fclose($fd);
211
                mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
212
        }
213

    
214
        interfaces_bring_up($qinqif);
215
        if (!empty($vlan['members'])) {
216
                $members = explode(" ", $vlan['members']);
217
                foreach ($members as $qif)
218
                        interfaces_bring_up("{$vlanif}_{$qif}");
219
        }
220

    
221
        return $vlanif;
222
}
223

    
224
function interfaces_qinq_configure() {
225
	global $config, $g;
226
	if($g['booting'])
227
		echo "Configuring QinQ interfaces...";
228
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
229
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
230
			/* XXX: Maybe we should report any errors?! */
231
			interface_qinq_configure($qinq);
232
		}
233
	}
234
	if($g['booting'])
235
		echo "done.\n";
236
}
237

    
238
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
239
        global $config, $g;
240

    
241
        if (!is_array($qinq)) {
242
                log_error("QinQ compat VLAN: called with wrong options. Problems with config!\n");
243
                return;
244
        }
245

    
246
        $if = $qinq['if'];
247
        $tag = $qinq['tag'];
248
        $vlanif = "{$if}_{$tag}";
249
        if(empty($if)) {
250
                log_error("interface_qinq_confgure called with if undefined.\n");
251
                return;
252
        }
253

    
254
        fwrite($fd, "shutdown {$if}h{$tag}:\n");
255
        fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
256
        fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
257
        fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
258
        fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
259
        fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
260

    
261
        /* invalidate interface cache */
262
        get_interface_arr(true);
263

    
264
        return $vlanif;
265
}
266

    
267
function interfaces_create_wireless_clones() {
268
	global $config;
269

    
270
	if($g['booting'])
271
		echo "Creating other wireless clone interfaces...";
272
	if (is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
273
		foreach ($config['wireless']['clone'] as $clone) {
274
			if(empty($clone['cloneif']))
275
				continue;
276
			if(does_interface_exist($clone['cloneif']))
277
				continue;
278
			/* XXX: Maybe we should report any errors?! */
279
			if(interface_wireless_clone($clone['cloneif'], $clone))
280
				if($g['booting'])
281
					echo " " . $clone['cloneif'];
282
		}
283
	}
284
	if($g['booting'])
285
		echo " done.\n";
286
}
287

    
288
function interfaces_bridge_configure() {
289
        global $config;
290

    
291
        $i = 0;
292
        if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
293
                foreach ($config['bridges']['bridged'] as $bridge) {
294
                        if(empty($bridge['bridgeif']))
295
                                $bridge['bridgeif'] = "bridge{$i}";
296
                        /* XXX: Maybe we should report any errors?! */
297
                        interface_bridge_configure($bridge);
298
                        $i++;
299
                }
300
        }
301
}
302

    
303
function interface_bridge_configure(&$bridge) {
304
	global $config, $g;
305

    
306
	if (!is_array($bridge))
307
	        return -1;
308

    
309
	if (empty($bridge['members'])) {
310
		log_error("No members found on {$bridge['bridgeif']}");
311
		return -1;
312
	}
313

    
314
	$members = explode(',', $bridge['members']);
315
	if (!count($members))
316
		return -1;
317

    
318
	$checklist = get_configured_interface_list();
319

    
320
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
321
		pfSense_interface_destroy($bridge['bridgeif']);
322
		pfSense_interface_create($bridge['bridgeif']);
323
		$bridgeif = $bridge['bridgeif'];
324
	} else
325
		$bridgeif = pfSense_interface_create("bridge");
326

    
327
	/* Calculate smaller mtu and enforce it */
328
	$smallermtu = 0;
329
	$commonrx = true;
330
	$commontx = true;
331
	foreach ($members as $member) {
332
		$realif = get_real_interface($member);
333
		$opts = pfSense_get_interface_addresses($realif);
334
		$mtu = $opts['mtu'];
335
		if (!isset($opts['encaps']['txcsum']))
336
			$commontx = false;
337
		if (!isset($opts['encaps']['rxcsum']))
338
			$commonrx = false;
339
		if ($smallermtu == 0 && !empty($mtu))
340
			$smallermtu = $mtu;
341
		else if (!empty($mtu) && $mtu < $smallermtu)
342
			$smallermtu = $mtu;
343
	}
344
	 
345
	/* Just in case anything is not working well */
346
	if ($smallermtu == 0)
347
		$smallermtu = 1500; 
348

    
349
	$flags = 0;
350
	if ($commonrx == false)
351
		$flags |= IFCAP_RXCSUM;
352
	if ($commontx == false)
353
		$flags |= IFCAP_TXCSUM;
354
		
355
	/* Add interfaces to bridge */
356
	foreach ($members as $member) {
357
		if (!array_key_exists($member, $checklist))
358
			continue;
359
		$realif1 = get_real_interface($member);
360
		$realif =  escapeshellarg($realif1);
361
		if (!$realif) {
362
			log_error("realif not defined in interfaces bridge - up");
363
			continue;
364
		}
365
		/* make sure the parent interface is up */
366
		pfSense_interface_mtu($realif1, $smallermtu);
367
		pfSense_interface_capabilities($realif1, -$flags);
368
		interfaces_bring_up($realif1);
369
		mwexec("/sbin/ifconfig {$bridgeif} addm {$realif}");	
370
	}
371

    
372
	if (isset($bridge['enablestp'])) {
373
		/* Choose spanning tree proto */
374
		mwexec("/sbin/ifconfig {$bridgeif} proto {$bridge['proto']}");	
375
		
376
		if (!empty($bridge['stp'])) {
377
			$stpifs = explode(',', $bridge['stp']);
378
			foreach ($stpifs as $stpif) {
379
				$realif = get_real_interface($stpif);
380
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
381
			}
382
		}
383
		if (!empty($bridge['maxage']))
384
			mwexec("/sbin/ifconfig {$bridgeif} maxage {$bridge['maxage']}");
385
		if (!empty($brige['fwdelay']))
386
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay {$bridge['fwdelay']}");
387
		if (!empty($brige['hellotime']))
388
                        mwexec("/sbin/ifconfig {$bridgeif} hellotime {$bridge['hellotime']}");
389
		if (!empty($brige['priority']))
390
                        mwexec("/sbin/ifconfig {$bridgeif} priority {$bridge['priority']}");
391
		if (!empty($brige['holdcount']))
392
                        mwexec("/sbin/ifconfig {$bridgeif} holdcnt {$bridge['holdcnt']}");
393
		if (!empty($bridge['ifpriority'])) {
394
			$pconfig = explode(",", $bridge['ifpriority']);
395
			$ifpriority = array();
396
			foreach ($pconfig as $cfg) {
397
				$embcfg = explode(":", $cfg);
398
				foreach ($embcfg as $key => $value)
399
					$ifpriority[$key] = $value;
400
			}
401
			foreach ($ifpriority as $key => $value) {
402
				$realif = get_real_interface($key);
403
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} {$value}"); 
404
			}
405
		}
406
		if (!empty($bridge['ifpathcost'])) {
407
			$pconfig = explode(",", $bridges['ifpathcost']);
408
			$ifpathcost = array();
409
			foreach ($pconfig as $cfg) {
410
				$embcfg = explode(":", $cfg);
411
				foreach ($embcfg as $key => $value)
412
					$ifpathcost[$key] = $value;
413
			}
414
			foreach ($ifpathcost as $key => $value) {
415
                        	$realif = get_real_interface($key);
416
                        	mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} {$value}");
417
                	}
418
		}
419
	}
420

    
421
	if ($bridge['maxaddr'] <> "")
422
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr {$bridge['maxaddr']}");
423
        if ($bridge['timeout'] <> "")
424
                mwexec("/sbin/ifconfig {$bridgeif} timeout {$bridge['timeout']}");
425
        if ($bridge['span'] <> "") {
426
		$realif = get_real_interface($bridge['span']);
427
                mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
428
	}
429
	if (!empty($bridge['edge'])) {
430
        	$edgeifs = explode(',', $bridge['edge']);
431
        	foreach ($edgeifs as $edgeif) {
432
			$realif = get_real_interface($edgeif);
433
                	mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
434
        	}
435
	}
436
	if (!empty($bridge['autoedge'])) {
437
        	$edgeifs = explode(',', $bridge['autoedge']);
438
        	foreach ($edgeifs as $edgeif) {
439
                	$realif = get_real_interface($edgeif);
440
                	mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
441
        	}
442
	}
443
	if (!empty($bridge['ptp'])) {
444
        	$ptpifs = explode(',', $bridge['ptp']);
445
        	foreach ($ptpifs as $ptpif) {
446
                	$realif = get_real_interface($ptpif);
447
                	mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
448
        	}
449
	}
450
	if (!empty($bridge['autoptp'])) {
451
        	$ptpifs = explode(',', $bridge['autoptp']);
452
        	foreach ($ptpifs as $ptpif) {
453
                	$realif = get_real_interface($ptpif);
454
                	mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
455
        	}
456
	}
457
	if (!empty($bridge['static'])) {
458
        	$stickyifs = explode(',', $bridge['static']);
459
        	foreach ($stickyifs as $stickyif) {
460
                	$realif = get_real_interface($stickyif);
461
                	mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
462
        	}
463
	}
464
	if (!empty($bridge['private'])) {
465
        	$privateifs = explode(',', $bridge['private']);
466
        	foreach ($privateifs as $privateif) {
467
                	$realif = get_real_interface($privateif);
468
               	 	mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
469
        	}
470
	}
471

    
472
	if($bridgeif)
473
		interfaces_bring_up($bridgeif);	
474
	else 
475
		log_error("bridgeif not defined -- could not bring interface up");
476

    
477
	return $bridgeif;
478
}
479

    
480
function interface_bridge_add_member($bridgeif, $interface) {
481

    
482
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
483
		return;
484

    
485
	$mtu = get_interface_mtu($brigeif);
486
	$mtum = get_interface_mtu($interface);
487
	
488
	if ($mtu != $mtum)
489
		pfSense_interface_mtu($interface, $mtu);
490

    
491
	$options = pfSense_get_interface_addresses($bridgeif);
492
	$flags = 0;
493
	if (!isset($options['encaps']['txcsum']))
494
		$flags |= IFCAP_TXCSUM;
495

    
496
	if (!isset($options['encaps']['rxcsum']))
497
		$flags |= IFCAP_RXCSUM;
498

    
499
	pfSense_interface_capabilities($interface, -$flags);
500

    
501
	interfaces_bring_up($interface);
502
	mwexec("/sbin/ifconfig {$bridgeif} addm {$interface}");
503
}
504

    
505
function interfaces_lagg_configure() 
506
{
507
        global $config, $g;
508
		if($g['booting']) 
509
			echo "Configuring LAGG interfaces...";
510
        $i = 0;
511
		if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
512
			foreach ($config['laggs']['lagg'] as $lagg) {
513
				if(empty($lagg['laggif']))
514
					$lagg['laggif'] = "lagg{$i}";
515
				/* XXX: Maybe we should report any errors?! */
516
				interface_lagg_configure($lagg);
517
				$i++;
518
			}
519
		}
520
		if($g['booting']) 
521
			echo "done.\n";
522
}
523

    
524
function interface_lagg_configure(&$lagg) {
525
        global $config, $g;
526

    
527
        if (!is_array($lagg))
528
		return -1;
529

    
530
	$members = explode(',', $lagg['members']);
531
	if (!count($members))
532
		return -1;
533
	
534
	$checklist = get_interface_list();
535

    
536
	if ($g['booting'] || !(empty($lagg['laggif']))) {
537
		pfSense_interface_destroy($lagg['laggif']);
538
		pfSense_interface_create($lagg['laggif']);
539
                $laggif = $lagg['laggif'];
540
        } else
541
		$laggif = pfSense_interface_create("lagg");
542

    
543
	/* Calculate smaller mtu and enforce it */
544
        $smallermtu = 0;
545
        foreach ($members as $member) {
546
                $mtu = get_interface_mtu($member);
547
		if ($smallermtu == 0 && !empty($mtu))
548
			$smallermtu = $mtu;
549
                else if (!empty($mtu) && $mtu < $smallermtu)
550
                        $smallermtu = $mtu;
551
        }
552

    
553
	/* Just in case anything is not working well */
554
        if ($smallermtu == 0)
555
                $smallermtu = 1500;
556

    
557
	foreach ($members as $member) {
558
		if (!array_key_exists($member, $checklist))
559
			continue;
560
		/* make sure the parent interface is up */
561
		pfSense_interface_mtu($member, $smallermtu);
562
		interfaces_bring_up($member);
563
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
564
	}
565
	
566
	mwexec("/sbin/ifconfig {$laggif} laggproto {$lagg['proto']}");
567

    
568
	interfaces_bring_up($laggif);
569

    
570
	return $laggif;
571
}
572

    
573
function interfaces_gre_configure() {
574
        global $config;
575

    
576
        $i = 0;
577
        if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
578
                foreach ($config['gres']['gre'] as $gre) {
579
                        if(empty($gre['greif']))
580
                                $gre['greif'] = "gre{$i}";
581
                        /* XXX: Maybe we should report any errors?! */
582
                        interface_gre_configure($gre);
583
                        $i++;
584
                }
585
        }
586
}
587

    
588
function interface_gre_configure(&$gre) {
589
        global $config, $g;
590

    
591
	if (!is_array($gre))
592
		return -1;
593

    
594
	$realif = get_real_interface($gre['if']);
595
	$realifip = get_interface_ip($gre['if']);
596

    
597
	/* make sure the parent interface is up */
598
	interfaces_bring_up($realif);
599

    
600
	if ($g['booting'] || !(empty($gre['greif']))) {
601
		pfSense_interface_destroy($gre['greif']);
602
		pfSense_interface_create($gre['greif']);
603
		$greif = $gre['greif'];
604
	} else
605
		$greif = pfSense_interface_create("gre");
606

    
607
	/* Do not change the order here for more see gre(4) NOTES section. */
608
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} {$gre['remote-addr']}");
609
	mwexec("/sbin/ifconfig {$greif} {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
610
	if (isset($gre['link0']) && $gre['link0'])
611
		pfSense_interface_flags($greif, IFF_LINK0);
612
	if (isset($gre['link1']) && $gre['link1'])
613
		pfSense_interface_flags($greif, IFF_LINK1);
614
	if (isset($gre['link2']) && $gre['link2'])
615
		pfSense_interface_flags($greif, IFF_LINK2);
616

    
617
	if($greif)
618
		interfaces_bring_up($greif);
619
	else 
620
		log_error("Could not bring greif up -- variable not defined.");
621

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

    
626
	return $greif;
627
}
628

    
629
function interfaces_gif_configure() {
630
	global $config;
631
	$i = 0;
632
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
633
		foreach ($config['gifs']['gif'] as $gif) {
634
			if(empty($gif['gifif']))
635
				$gre['gifif'] = "gif{$i}";
636
			/* XXX: Maybe we should report any errors?! */
637
			interface_gif_configure($gif);
638
			$i++;
639
		}
640
	}
641
}
642

    
643
function interface_gif_configure(&$gif) {
644
	global $config, $g;
645

    
646
	if (!is_array($gif))
647
		return -1;
648

    
649
	$realif = get_real_interface($gif['if']);
650
	$realifip = get_interface_ip($gif['if']);
651

    
652
	/* make sure the parent interface is up */
653
	if($realif)
654
		interfaces_bring_up($realif);
655
	else 
656
		log_error("could not bring realif up -- variable not defined -- interface_gif_configure()");
657

    
658
	if ($g['booting'] || !(empty($gif['gifif']))) {
659
		pfSense_interface_destroy($gif['gifif']);
660
		pfSense_interface_create($gif['gifif']);
661
		$gifif = $gif['gifif'];
662
	} else
663
		$gifif = pfSense_interface_create("gif");
664

    
665
	/* Do not change the order here for more see gif(4) NOTES section. */
666
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} {$gif['remote-addr']}");
667
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
668
		mwexec("/sbin/ifconfig {$gifif} inet6 {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} prefixlen {$gif['tunnel-remote-net']} ");
669
	} else {
670
		mwexec("/sbin/ifconfig {$gifif} {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
671
	}
672
	if (isset($gif['link0']) && $gif['link0'])
673
		pfSense_interface_flags($gifif, IFF_LINK0);
674
	if (isset($gif['link1']) && $gif['link1'])
675
		pfSense_interface_flags($gifif, IFF_LINK1);
676
	if($gifif)
677
		interfaces_bring_up($gifif);
678
	else
679
		log_error("could not bring gifif up -- variable not defined");
680

    
681
	/* XXX: Needed?! Let them use the defined gateways instead */
682
	//mwexec("/sbin/route add {$gif['tunnel-remote-addr']}/{$gif['tunnel-remote-net']} -iface {$gifif}");
683
	file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
684

    
685
	return $gifif;
686
}
687

    
688
function interfaces_configure() {
689
	global $config, $g;
690

    
691
	/* Set up our loopback interface */
692
	interfaces_loopback_configure();
693

    
694
	/* set up LAGG virtual interfaces */
695
	interfaces_lagg_configure();
696

    
697
	/* set up VLAN virtual interfaces */
698
	interfaces_vlan_configure();
699

    
700
	interfaces_qinq_configure();
701

    
702
	$iflist = get_configured_interface_with_descr();
703
	$delayed_list = array();
704
	$bridge_list = array();
705
	
706
	/* This is needed to speedup interfaces on bootup. */
707
	$reload = false;
708
	if ($g['booting'])
709
		$reload = true;
710

    
711
	foreach($iflist as $if => $ifname) {
712
		$realif = $config['interfaces'][$if]['if'];
713
		if (strstr($realif, "bridge")) 
714
			$bridge_list[$if] = $ifname;
715
		else if (strstr($realif, "gre"))
716
			$delayed_list[$if] = $ifname;
717
		else if (strstr($realif, "gif"))
718
			$delayed_list[$if] = $ifname;
719
		else if (strstr($realif, "ovpn")) {
720
			//echo "Delaying OpenVPN interface configuration...done.\n";
721
			continue;
722
		} else {
723
			if ($g['booting'])
724
				echo "Configuring {$ifname} interface...";
725
			if($g['debug'])
726
				log_error("Configuring {$ifname}");
727
			interface_configure($if, $reload);
728
			if ($g['booting']) 
729
				echo "done.\n";
730
		}
731
	}
732

    
733
	/* create the unconfigured wireless clones */
734
	interfaces_create_wireless_clones();
735

    
736
	/* set up GRE virtual interfaces */
737
	interfaces_gre_configure();
738

    
739
	/* set up GIF virtual interfaces */
740
	interfaces_gif_configure();
741
	
742
	foreach ($delayed_list as $if => $ifname) {
743
		if ($g['booting'])
744
			echo "Configuring {$ifname} interface...";
745
        	if ($g['debug'])
746
        		log_error("Configuring {$ifname}");
747

    
748
		interface_configure($if, $reload);
749

    
750
		if ($g['booting'])
751
			echo "done.\n";
752
	}
753

    
754
	/* set up BRIDGe virtual interfaces */
755
	interfaces_bridge_configure();
756

    
757
	foreach ($bridge_list as $if => $ifname) {
758
		if ($g['booting'])
759
			echo "Configuring {$ifname} interface...";
760
		if($g['debug'])
761
			log_error("Configuring {$ifname}");
762

    
763
		interface_configure($if, $reload);
764

    
765
		if ($g['booting'])
766
			echo "done.\n";
767
	}
768

    
769
	/* bring up vip interfaces */
770
	interfaces_vips_configure();
771

    
772
	/* configure interface groups */
773
	interfaces_group_setup();
774

    
775
	if (!$g['booting']) {
776
		/* reconfigure static routes (kernel may have deleted them) */
777
		system_routing_configure();
778

    
779
		/* reload IPsec tunnels */
780
		vpn_ipsec_configure();
781

    
782
		/* reload dhcpd (interface enabled/disabled status may have changed) */
783
		services_dhcpd_configure();
784

    
785
		/* restart dnsmasq */
786
		services_dnsmasq_configure();
787

    
788
		/* reload captive portal */
789
		captiveportal_init_rules();
790

    
791
		/* set the reload filter dity flag */
792
		filter_configure();
793
	}
794

    
795
	return 0;
796
}
797

    
798
function interface_reconfigure($interface = "wan") {
799
	interface_bring_down($interface);
800
	interface_configure($interface, true);
801
}
802

    
803
function interface_vip_bring_down($vip) {
804
	global $g;
805

    
806
	switch ($vip['mode']) {
807
	case "proxyarp":
808
		$vipif = get_real_interface($vip['interface']);
809
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
810
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
811
		break;
812
	case "ipalias":
813
		$vipif = get_real_interface($vip['interface']);
814
		if(does_interface_exist($vipif))
815
			pfSense_interface_deladdress($vipif, $vip['subnet']);
816
		break;
817
	case "carp":
818
		$vipif = "vip" . $vip['vhid'];
819
		if(does_interface_exist($vipif)) 
820
			pfSense_interface_destroy($vipif);
821
		break;
822
	case "carpdev-dhcp":
823
		$vipif = "vip" . $vip['vhid'];
824
		if(does_interface_exist($vipif)) 
825
			pfSense_interface_destroy($vipif);
826
		break;
827
	}
828
}
829

    
830
function interface_bring_down($interface = "wan", $destroy = false) {
831
	global $config, $g;
832

    
833
	if (!isset($config['interfaces'][$interface]))
834
		return; 
835

    
836
	$ifcfg = $config['interfaces'][$interface];
837

    
838
	$realif = get_real_interface($interface);
839

    
840
	switch ($ifcfg['ipaddr']) {
841
	case "ppp":
842
	case "pppoe":
843
	case "pptp":
844
	case "l2tp":
845
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
846
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
847
				if ($realif == $ppp['if']) {
848
					if (file_exists("{$g['varrun_path']}/{$ifcfg['ipaddr']}_{$interface}.pid")) {
849
						killbypid("{$g['varrun_path']}/{$ifcfg['ipaddr']}_{$interface}.pid");
850
						sleep(5);
851
					}
852
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
853
					if (isset($ppp['ondemand']) && !$destroy)
854
						send_event("interface reconfigure {$interface}");
855
					break;
856
				}
857
			}
858
		}
859
		break;
860
	case "carpdev-dhcp":
861
		/* 
862
		 * NB: When carpdev gets enabled it would be better to be handled as all
863
		 *	   other interfaces! 
864
		 */
865
	case "dhcp":
866
		$pid = find_dhclient_process($realif);
867
		if($pid)
868
			mwexec("kill {$pid}");
869
		sleep(1);
870
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
871
		if(does_interface_exist("$realif")) {
872
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
873
			if ($destroy == true)
874
				pfSense_interface_flags($realif, -IFF_UP);
875
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
876
		}
877
		break;
878
	default:
879
		if(does_interface_exist("$realif")) {
880
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
881
			if ($destroy == true)
882
				pfSense_interface_flags($realif, -IFF_UP);
883
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
884
		}
885
		break;
886
	}
887

    
888
	/* remove interface up file if it exists */
889
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
890
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
891
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
892
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
893
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
894
	
895
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
896
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
897
	if (is_array($ifcfg['wireless'])) {
898
		mwexec(kill_hostapd($realif));
899
		mwexec(kill_wpasupplicant($realif));
900
	}
901

    
902
	if ($destroy == true) {
903
		if (preg_match("/^vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan/i", $realif))
904
			pfSense_interface_destroy($realif);
905
	}	
906

    
907
	return;
908
}
909

    
910
function interfaces_ptpid_used($ptpid) {
911
	global $config;
912

    
913
	if (is_array($config['ppps']['ppp']))
914
		foreach ($config['ppps']['ppp'] as & $settings)
915
			if ($ptpid == $settings['ptpid'])
916
				return true;
917

    
918
	return false;
919
}
920

    
921
function interfaces_ptpid_next() {
922

    
923
	$ptpid = 0;
924
	while(interfaces_ptpid_used($ptpid))
925
		$ptpid++;
926

    
927
	return $ptpid;
928
}
929

    
930
function getMPDCRONSettings($pppif_) {
931
	global $config;
932
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
933
	if (is_array($config['cron']['item'])) {
934
		for ($i = 0; $i < count($config['cron']['item']); $i++) {
935
			$item = $config['cron']['item'][$i];
936
			if (strpos($item['command'], $cron_cmd_file.$pppif_) !== false) {
937
				return array("ID" => $i, "ITEM" => $item);
938
			}
939
		}
940
	}
941
	return NULL;
942
}
943

    
944
function handle_pppoe_reset($post_array) {
945
	global $config, $g;
946

    
947
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
948

    
949
	$pppif = $post_array['type'].$post_array['ptpid'];
950
	if (!is_array($config['cron']['item'])) 
951
		$config['cron']['item'] = array(); 
952
	$itemhash = getMPDCRONSettings($pppif);
953
	$item = $itemhash['ITEM'];
954
	
955
	// reset cron items if necessary and return
956
	if (empty($post_array['pppoe-reset-type'])) {
957
		if (isset($item))
958
			unset($config['cron']['item'][$itemhash['ID']]);
959
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
960
		return;
961
	}
962

    
963
	if (empty($item)) 
964
		$item = array();
965
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
966
		$item['minute'] = $post_array['pppoe_resetminute'];
967
		$item['hour'] = $post_array['pppoe_resethour'];
968
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
969
			$date = explode("/", $post_array['pppoe_resetdate']);
970
			$item['mday'] = $date[1];
971
			$item['month'] = $date[0];
972
		} else {
973
			$item['mday'] = "*";
974
			$item['month'] = "*";
975
		}
976
		$item['wday'] = "*";
977
		$item['who'] = "root";
978
		$item['command'] = $cron_cmd_file.$pppif;
979
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
980
		switch ($post_array['pppoe_pr_preset_val']) {
981
			case "monthly":
982
				$item['minute'] = "0";
983
				$item['hour'] = "0";
984
				$item['mday'] = "1";
985
				$item['month'] = "*";
986
				$item['wday'] = "*";
987
				$item['who'] = "root";
988
				$item['command'] = $cron_cmd_file.$pppif;
989
				break;
990
	        case "weekly":
991
				$item['minute'] = "0";
992
				$item['hour'] = "0";
993
				$item['mday'] = "*";
994
				$item['month'] = "*";
995
				$item['wday'] = "0";
996
				$item['who'] = "root";
997
				$item['command'] = $cron_cmd_file.$pppif;
998
				break;
999
			case "daily":
1000
				$item['minute'] = "0";
1001
				$item['hour'] = "0";
1002
				$item['mday'] = "*";
1003
				$item['month'] = "*";
1004
				$item['wday'] = "*";
1005
				$item['who'] = "root";
1006
				$item['command'] = $cron_cmd_file.$pppif;
1007
				break;
1008
			case "hourly":
1009
				$item['minute'] = "0";
1010
				$item['hour'] = "*";
1011
				$item['mday'] = "*";
1012
				$item['month'] = "*";
1013
				$item['wday'] = "*";
1014
				$item['who'] = "root";
1015
				$item['command'] = $cron_cmd_file.$pppif;
1016
				break;
1017
		} // end switch
1018
	} else {
1019
		/* test whether a cron item exists and unset() it if necessary */
1020
		$itemhash = getMPDCRONSettings($pppif);
1021
		$item = $itemhash['ITEM'];
1022
		if (isset($item))
1023
			unset($config['cron']['item'][$itemhash['ID']]); 
1024
	}// end if
1025
	if (isset($itemhash['ID'])) 
1026
		$config['cron']['item'][$itemhash['ID']] = $item;
1027
	else 
1028
		$config['cron']['item'][] = $item;
1029
}
1030

    
1031
/*	This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1032
*	It writes the mpd config file to /var/etc every time the link is opened.
1033
*/
1034

    
1035
function interface_ppps_configure($interface) {
1036
	global $config, $g;
1037
	
1038
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1039
	if(!is_dir("/var/spool/lock")) {
1040
		exec("/bin/mkdir -p /var/spool/lock");
1041
		exec("/bin/chmod a+rw /var/spool/lock/.");
1042
	}
1043
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files	
1044
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1045
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1046
		
1047
	$ifcfg = $config['interfaces'][$interface];
1048
	if (!isset($ifcfg['enable']))
1049
		return 0;
1050
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1051
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1052
			if ($ifcfg['if'] == $ppp['if'])
1053
				break;
1054
		}
1055
	}
1056
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1057
		log_error("Can't find PPP config for {$ifcfg['if']} in interface_ppps_configure().");
1058
		return 0;
1059
	}
1060
	$pppif = $ifcfg['if'];
1061
	if ($ppp['type'] == "ppp")
1062
		$type = "modem";
1063
	else
1064
		$type = $ppp['type'];
1065
	$upper_type = strtoupper($ppp['type']);	
1066
	
1067
	if($g['booting']) {
1068
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1069
		echo "starting {$pppif} link...";
1070
		// Do not re-configure the interface if we are booting and it's already been started
1071
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1072
			return 0;
1073
	}
1074
	
1075
	$ports = explode(',',$ppp['ports']);
1076
	if ($type != "modem") {
1077
		foreach ($ports as $pid => $port)
1078
			$ports[$pid] = get_real_interface($port);
1079
	}
1080
	$localips = explode(',',$ppp['localip']);
1081
	$gateways = explode(',',$ppp['gateway']);
1082
	$subnets = explode(',',$ppp['subnet']);
1083
	
1084
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1085
	to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1086
	*/
1087
	foreach($ports as $pid => $port){
1088
		switch ($ppp['type']) {
1089
			case "pppoe": 
1090
				/* Bring the parent interface up */
1091
				interfaces_bring_up($port);
1092
				break;
1093
			case "pptp":
1094
			case "l2tp":
1095
				/* configure interface */
1096
				if(is_ipaddr($localips[$pid])){
1097
					// Manually configure interface IP/subnet
1098
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1099
					interfaces_bring_up($port);
1100
				} else if (empty($localips[$pid]))
1101
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1102
				
1103
				if(!is_ipaddr($localips[$pid])){
1104
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure.");
1105
					return 0;
1106
				}
1107
				/* XXX: This needs to go away soon! [It's commented out!] */
1108
				/* Configure the gateway (remote IP ) */
1109
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1110
					/* XXX: Fix later 
1111
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1112
					if(!is_ipaddr($gateways[$pid])) {
1113
						log_error("Could not get a valid Gateway IP from {$port} via DNS in interfaces_ppps_configure.");
1114
						return 0;
1115
					}
1116
					*/
1117
				}
1118
				if(!is_ipaddr($gateways[$pid])){
1119
					log_error("Could not get a PPTP/L2TP Remote IP address from {$dhcp_gateway} for {$gway} in interfaces_ppps_configure.");
1120
					return 0;
1121
				}
1122
				break;
1123
			case "ppp":
1124
				if (!file_exists("{$port}")) {
1125
					log_error("Device {$port} does not exist. PPP link cannot start without the modem device.");
1126
					return 0;
1127
				}
1128
				break;
1129
			default:
1130
				log_error("Unkown {$type} configured as ppp interface.");
1131
				break;
1132
		}
1133
	}
1134
	
1135
	if (is_array($ports) && count($ports) > 1)
1136
		$multilink = "enable";
1137
	else
1138
		$multilink = "disable";
1139
	
1140
	if ($type == "modem"){
1141
		if (is_ipaddr($ppp['localip']))
1142
			$localip = $ppp['localip'];
1143
		else
1144
			$localip = '0.0.0.0';
1145

    
1146
		if (is_ipaddr($ppp['gateway']))
1147
			$gateway = $ppp['gateway'];
1148
		else
1149
			$gateway = "10.64.64.{$pppid}";
1150
		$ranges = "{$localip}/0 {$gateway}/0";
1151
		
1152
		if (empty($ppp['apnum']))	
1153
			$ppp['apnum'] = 1;
1154
	} else
1155
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1156

    
1157
	if (isset($ppp['ondemand'])) 
1158
		$ondemand = "enable";
1159
	else
1160
		$ondemand = "disable";
1161
	if (!isset($ppp['idletimeout']))
1162
		$ppp['idletimeout'] = 0;
1163

    
1164
	if (empty($ppp['username']) && $type == "modem"){
1165
		$ppp['username'] = "user";
1166
		$ppp['password'] = "none";
1167
	}
1168
	if (empty($ppp['password']) && $type == "modem")
1169
		$passwd = "none";
1170
	else
1171
		$passwd = base64_decode($ppp['password']);
1172

    
1173
	$bandwidths = explode(',',$ppp['bandwidth']);
1174
	$mtus = explode(',',$ppp['mtu']);
1175
	$mrus = explode(',',$ppp['mru']);
1176

    
1177
	if (isset($ppp['mrru']))
1178
		$mrrus = explode(',',$ppp['mrru']);
1179

    
1180
	// Construct the mpd.conf file
1181
	$mpdconf = <<<EOD
1182
startup:
1183
	# configure the console
1184
	set console close
1185
	# configure the web server
1186
	set web close
1187

    
1188
default:
1189
{$ppp['type']}client:
1190
	create bundle static {$interface}
1191
	set iface name {$pppif}
1192

    
1193
EOD;
1194
	$setdefaultgw = false;
1195
	$founddefaultgw = false;
1196
	if (is_array($config['gateways']['gateway_item'])) {
1197
		foreach($config['gateways']['gateway_item'] as $gateway) {
1198
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1199
				$setdefaultgw = true;
1200
				break;
1201
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1202
				$founddefaultgw = true;
1203
				break;
1204
			}
1205
		}
1206
	}
1207
	
1208
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1209
		$setdefaultgw = true;
1210
		$mpdconf .= <<<EOD
1211
	set iface route default
1212

    
1213
EOD;
1214
	}
1215
	$mpdconf .= <<<EOD
1216
	set iface {$ondemand} on-demand
1217
	set iface idle {$ppp['idletimeout']}
1218

    
1219
EOD;
1220

    
1221
	if (isset($ppp['ondemand']))
1222
		$mpdconf .= <<<EOD
1223
	set iface addrs 10.10.1.1 10.10.1.2
1224

    
1225
EOD;
1226
	
1227
	if (isset($ppp['tcpmssfix']))
1228
		$tcpmss = "disable";
1229
	else
1230
		$tcpmss = "enable";
1231
		$mpdconf .= <<<EOD
1232
	set iface {$tcpmss} tcpmssfix
1233

    
1234
EOD;
1235

    
1236
	$mpdconf .= <<<EOD
1237
	set iface up-script /usr/local/sbin/ppp-linkup
1238
	set iface down-script /usr/local/sbin/ppp-linkdown
1239
	set ipcp ranges {$ranges}
1240

    
1241
EOD;
1242
	if (isset($ppp['vjcomp']))
1243
		$mpdconf .= <<<EOD
1244
	set ipcp no vjcomp
1245

    
1246
EOD;
1247

    
1248
	if (isset($config['system']['dnsallowoverride']))
1249
		$mpdconf .= <<<EOD
1250
	set ipcp enable req-pri-dns
1251
	set ipcp enable req-sec-dns
1252

    
1253
EOD;
1254
	if (!isset($ppp['verbose_log']))
1255
		$mpdconf .= <<<EOD
1256
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1257

    
1258
EOD;
1259
	foreach($ports as $pid => $port){
1260
		$port = get_real_interface($port);
1261
		$mpdconf .= <<<EOD
1262

    
1263
	create link static {$interface}_link{$pid} {$type}
1264
	set link action bundle {$interface}
1265
	set link {$multilink} multilink
1266
	set link keep-alive 10 60
1267
	set link max-redial 0
1268

    
1269
EOD;
1270
		if (isset($ppp['shortseq']))
1271
			$mpdconf .= <<<EOD
1272
	set link no shortseq
1273

    
1274
EOD;
1275

    
1276
		if (isset($ppp['acfcomp']))
1277
			$mpdconf .= <<<EOD
1278
	set link no acfcomp
1279

    
1280
EOD;
1281

    
1282
		if (isset($ppp['protocomp']))
1283
			$mpdconf .= <<<EOD
1284
	set link no protocomp
1285

    
1286
EOD;
1287

    
1288
		$mpdconf .= <<<EOD
1289
	set link disable chap pap
1290
	set link accept chap pap eap
1291
	set link disable incoming
1292

    
1293
EOD;
1294

    
1295

    
1296
		if (!empty($bandwidths[$pid]))
1297
			$mpdconf .= <<<EOD
1298
	set link bandwidth {$bandwidths[$pid]}
1299

    
1300
EOD;
1301

    
1302
		if (empty($mtus[$pid]))
1303
			$mtus[$pid] = "1492";
1304
			$mpdconf .= <<<EOD
1305
	set link mtu {$mtus[$pid]}
1306

    
1307
EOD;
1308

    
1309
		if (!empty($mrus[$pid]))
1310
			$mpdconf .= <<<EOD
1311
	set link mru {$mrus[$pid]}
1312

    
1313
EOD;
1314

    
1315
		if (!empty($mrrus[$pid]))
1316
			$mpdconf .= <<<EOD
1317
	set link mrru {$mrrus[$pid]}
1318

    
1319
EOD;
1320

    
1321
		$mpdconf .= <<<EOD
1322
	set auth authname "{$ppp['username']}"
1323
	set auth password {$passwd}
1324

    
1325
EOD;
1326
		if ($type == "modem") {
1327
			$mpdconf .= <<<EOD
1328
	set modem device {$ppp['ports']}
1329
	set modem script DialPeer
1330
	set modem idle-script Ringback
1331
	set modem watch -cd
1332
	set modem var \$DialPrefix "DT"
1333
	set modem var \$Telephone "{$ppp['phone']}"
1334

    
1335
EOD;
1336
		}
1337
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1338
			$mpdconf .= <<<EOD
1339
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1340

    
1341
EOD;
1342
		}
1343
		if (isset($ppp['initstr']) && $type == "modem") {
1344
			$initstr = base64_decode($ppp['initstr']);
1345
			$mpdconf .= <<<EOD
1346
	set modem var \$InitString "{$initstr}"
1347

    
1348
EOD;
1349
		}
1350
		if (isset($ppp['simpin']) && $type == "modem") {
1351
			$mpdconf .= <<<EOD
1352
	set modem var \$SimPin "{$ppp['simpin']}"
1353
	set modem var \$PinWait "{$ppp['pin-wait']}"
1354

    
1355
EOD;
1356
		}
1357
		if (isset($ppp['apn']) && $type == "modem") {
1358
			$mpdconf .= <<<EOD
1359
	set modem var \$APN "{$ppp['apn']}"
1360
	set modem var \$APNum "{$ppp['apnum']}"
1361

    
1362
EOD;
1363
		}
1364
		if (isset($ppp['provider']) && $type == "pppoe") {
1365
			$mpdconf .= <<<EOD
1366
	set pppoe service "{$ppp['provider']}"
1367

    
1368
EOD;
1369
		}
1370
		if ($type == "pppoe")
1371
			$mpdconf .= <<<EOD
1372
	set pppoe iface {$port}
1373

    
1374
EOD;
1375

    
1376
		if ($type == "pptp" || $type == "l2tp") {
1377
			$mpdconf .= <<<EOD
1378
	set {$type} self {$localips[$pid]}
1379
	set {$type} peer {$gateways[$pid]}
1380
	set {$type} disable windowing
1381

    
1382
EOD;
1383
		}
1384
		
1385
		$mpdconf .= "\topen\r\n";
1386
	} //end foreach($port)
1387

    
1388

    
1389
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1390
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1391
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1392
	else {
1393
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1394
		if (!$fd) {
1395
			log_error("Error: cannot open mpd_{$interface}.conf in interface_ppps_configure().\n");
1396
			return 0;
1397
		}
1398
		// Write out mpd_ppp.conf
1399
		fwrite($fd, $mpdconf);
1400
		fclose($fd);
1401
	}
1402

    
1403
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1404
	if (isset($ppp['uptime'])) {
1405
		if (!file_exists("/conf/{$pppif}.log")) {
1406
			conf_mount_rw();
1407
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1408
			conf_mount_ro();
1409
		}
1410
	} else {
1411
		if (file_exists("/conf/{$pppif}.log")) {
1412
			conf_mount_rw();
1413
			mwexec("rm -f /conf/{$pppif}.log");
1414
			conf_mount_ro();
1415
		}
1416
	}
1417
		
1418
	/* fire up mpd */
1419
	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");
1420

    
1421
	// Check for PPPoE periodic reset request 
1422
	if ($type == "pppoe") {
1423
		if (isset($ppp['pppoe-reset-type']))
1424
			setup_pppoe_reset_file($ppp['if'], $interface);
1425
		else
1426
			setup_pppoe_reset_file($ppp['if']);
1427
	}
1428

    
1429
	return 1;
1430
}
1431

    
1432
function interfaces_carp_setup() {
1433
	global $g, $config;
1434

    
1435
	$balanacing = "";
1436
	$pfsyncinterface = "";
1437
	$pfsyncenabled = "";
1438
	if(isset($config['system']['developerspew'])) {
1439
		$mt = microtime();
1440
		echo "interfaces_carp_setup() being called $mt\n";
1441
	}
1442

    
1443
	// Prepare CmdCHAIN that will be used to execute commands.
1444
	$cmdchain = new CmdCHAIN();	
1445

    
1446
	if ($g['booting']) {
1447
		echo "Configuring CARP settings...";
1448
		mute_kernel_msgs();
1449
	}
1450

    
1451
	/* suck in configuration items */
1452
	if($config['installedpackages']['carpsettings']) {
1453
		if($config['installedpackages']['carpsettings']['config']) {
1454
			foreach($config['installedpackages']['carpsettings']['config'] as $carp) {
1455
				$pfsyncenabled = $carp['pfsyncenabled'];
1456
				$balanacing = $carp['balancing'];
1457
				$pfsyncinterface = $carp['pfsyncinterface'];
1458
				$pfsyncpeerip = $carp['pfsyncpeerip'];
1459
			}
1460
		}
1461
	} else {
1462
		unset($pfsyncinterface);
1463
		unset($balanacing);
1464
		unset($pfsyncenabled);
1465
	}
1466

    
1467
	$cmdchain->add("Allow CARP", "/sbin/sysctl net.inet.carp.allow=1", true);			
1468
	if($balanacing) {
1469
		$cmdchain->add("Enable CARP ARP-balancing", "/sbin/sysctl net.inet.carp.arpbalance=1", true);
1470
		$cmdchain->add("Disallow CARP preemption", "/sbin/sysctl net.inet.carp.preempt=0", true);
1471
	} else
1472
		$cmdchain->add("Enable CARP preemption", "/sbin/sysctl net.inet.carp.preempt=1", true);		
1473

    
1474
	$cmdchain->add("Enable CARP logging", "/sbin/sysctl net.inet.carp.log=2", true);
1475
	if (!empty($pfsyncinterface))
1476
		$carp_sync_int = get_real_interface($pfsyncinterface);
1477

    
1478
	if($g['booting']) {
1479
		/*    install rules to alllow pfsync to sync up during boot
1480
		 *    carp interfaces will remain down until the bootup sequence finishes
1481
		 */
1482
		$fd = fopen("{$g['tmp_path']}/rules.boot", "w");
1483
		if ($fd) {
1484
			fwrite($fd, "pass quick proto carp all keep state\n");
1485
			fwrite($fd, "pass quick proto pfsync all\n");
1486
			fwrite($fd, "pass out quick from any to any keep state\n");
1487
			fclose($fd);
1488
			mwexec("/sbin/pfctl -f {$g['tmp_path']}/rules.boot");
1489
		} else
1490
			log_error("Could not create rules.boot file!");
1491
	}
1492

    
1493
	/* setup pfsync interface */
1494
	if($carp_sync_int and $pfsyncenabled) {
1495
		if (is_ipaddr($pfsyncpeerip))
1496
			$cmdchain->add("Bring up pfsync0 syncpeer", "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} syncpeer {$pfsyncpeerip} up", false);						
1497
		else
1498
			$cmdchain->add("Bring up pfsync0 syncdev", "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} up", false);			
1499
	} else
1500
		$cmdchain->add("Bring up pfsync0", "/sbin/ifconfig pfsync0 syncdev lo0 up", false);						
1501

    
1502
	if($config['virtualip']['vip'])
1503
		$cmdchain->add("Allow CARP.", "/sbin/sysctl net.inet.carp.allow=1", true);				
1504
	else
1505
		$cmdchain->add("Disallow CARP.", "/sbin/sysctl net.inet.carp.allow=0", true);		
1506
	
1507
	if($g['debug'])
1508
		$cmdchain->setdebug(); // optional for verbose logging
1509

    
1510
	$cmdchain->execute();
1511
	$cmdchain->clear();
1512

    
1513
	if ($g['booting']) {
1514
		unmute_kernel_msgs();
1515
		echo "done.\n";
1516
	}
1517
}
1518

    
1519
function interface_proxyarp_configure($interface = "") {
1520
	global $config, $g;
1521
	if(isset($config['system']['developerspew'])) {
1522
		$mt = microtime();
1523
		echo "interface_proxyarp_configure() being called $mt\n";
1524
	}
1525

    
1526
	/* kill any running choparp */
1527
	if (empty($interface))
1528
		killbyname("choparp");
1529
	else {
1530
		$vipif = get_real_interface($interface);
1531
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1532
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1533
	}
1534

    
1535
	$paa = array();
1536
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1537

    
1538
		/* group by interface */
1539
		foreach ($config['virtualip']['vip'] as $vipent) {
1540
			if ($vipent['mode'] === "proxyarp") {
1541
				if ($vipent['interface'])
1542
					$proxyif = $vipent['interface'];
1543
				else
1544
					$proxyif = "wan";
1545
				
1546
				if (!empty($interface) && $interface != $proxyif)
1547
					continue;
1548

    
1549
				if (!is_array($paa[$proxyif]))
1550
					$paa[$proxyif] = array();
1551

    
1552
				$paa[$proxyif][] = $vipent;
1553
			}
1554
		}
1555
	}
1556

    
1557
	if (!empty($interface)) {
1558
		if (is_array($paa[$interface])) {
1559
			$paaifip = get_interface_ip($interface);
1560
                        if (!is_ipaddr($paaifip))
1561
                                return;
1562
                        $args = get_real_interface($interface) . " auto";
1563
                        foreach ($paa[$interface] as $paent) {
1564
                                if (isset($paent['subnet']))
1565
                                        $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1566
                                else if (isset($paent['range']))
1567
                                        $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1568
                        }
1569
                        mwexec_bg("/usr/local/sbin/choparp " . $args);	
1570
		}
1571
	} else if (count($paa) > 0) {
1572
		foreach ($paa as $paif => $paents)  {
1573
			$paaifip = get_interface_ip($paif);
1574
			if (!is_ipaddr($paaifip))
1575
				continue;
1576
			$args = get_real_interface($paif) . " auto";
1577
			foreach ($paents as $paent) {
1578
				if (isset($paent['subnet']))
1579
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1580
				else if (isset($paent['range']))
1581
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1582
			}
1583
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1584
		}
1585
	}
1586
}
1587

    
1588
function interfaces_vips_configure($interface = "") {
1589
	global $g, $config;
1590
	if(isset($config['system']['developerspew'])) {
1591
		$mt = microtime();
1592
		echo "interfaces_vips_configure() being called $mt\n";
1593
	}
1594
	$paa = array();
1595
	if(is_array($config['virtualip']['vip'])) {
1596
		$carp_setuped = false;
1597
		$anyproxyarp = false;
1598
		foreach ($config['virtualip']['vip'] as $vip) {
1599
			switch ($vip['mode']) {
1600
			case "proxyarp":
1601
				/* nothing it is handled on interface_proxyarp_configure() */
1602
				if ($interface <> "" && $vip['interface'] <> $interface)
1603
					continue;
1604
				$anyproxyarp = true;
1605
				break;
1606
			case "ipalias":
1607
				if ($interface <> "" && $vip['interface'] <> $interface)
1608
					continue;
1609
				interface_ipalias_configure(&$vip);
1610
				break;
1611
			case "carp":
1612
				if ($interface <> "" && $vip['interface'] <> $interface)
1613
					continue;
1614
				if ($carp_setuped == false) {
1615
					interfaces_carp_setup();
1616
					$carp_setuped = true;
1617
				}
1618
				interface_carp_configure($vip);
1619
				break;
1620
			case "carpdev-dhcp":
1621
				if ($interface <> "" && $vip['interface'] <> $interface)
1622
					continue;
1623
				interface_carpdev_configure($vip);
1624
				break;
1625
			}
1626
		}
1627
		
1628
		if ($anyproxyarp == true)
1629
			interface_proxyarp_configure();
1630
	}
1631
}
1632

    
1633
function interface_ipalias_configure(&$vip) {
1634

    
1635
	if ($vip['mode'] == "ipalias") {
1636
		$if = get_real_interface($vip['interface']);
1637
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $vip['subnet'] . "/" . escapeshellarg($vip['subnet_bits']) . " alias");
1638
	}
1639
}
1640

    
1641
function interface_reload_carps($cif) {
1642
	global $config;
1643

    
1644
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
1645
	if (empty($carpifs))
1646
		return;
1647

    
1648
	$carps = explode(" ", $carpifs);
1649
	if(is_array($config['virtualip']['vip'])) {
1650
		$viparr = &$config['virtualip']['vip'];
1651
		foreach ($viparr as $vip) {
1652
			if (in_array($vip['carpif'], $carps)) {
1653
				switch ($vip['mode']) {
1654
				case "carp":
1655
					interface_vip_bring_down($vip);
1656
					sleep(1);
1657
					interface_carp_configure($vip);
1658
					break;
1659
				case "carpdev-dhcp":
1660
					interface_vip_bring_down($vip);
1661
					sleep(1);
1662
					interface_carpdev_configure($vip);
1663
					break;
1664
				case "ipalias":
1665
					interface_vip_bring_down($vip);
1666
					sleep(1);
1667
					interface_ipalias_configure($vip);
1668
					break;
1669
				}
1670
			}
1671
		}
1672
	}
1673
}
1674

    
1675
function interface_carp_configure(&$vip) {
1676
	global $config, $g;
1677
	if(isset($config['system']['developerspew'])) {
1678
		$mt = microtime();
1679
		echo "interface_carp_configure() being called $mt\n";
1680
	}
1681

    
1682
	if ($vip['mode'] != "carp")
1683
		return;
1684

    
1685
	$vip_password = $vip['password'];
1686
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
1687
	if ($vip['password'] != "")
1688
		$password = " pass {$vip_password}";
1689

    
1690
	// set the vip interface to the vhid
1691
	$vipif = "vip{$vip['vhid']}";
1692

    
1693
	$interface = interface_translate_type_to_real($vip['interface']);
1694
	/*
1695
	 * ensure the interface containing the VIP really exists
1696
 	 * prevents a panic if the interface is missing or invalid
1697
	 */
1698
	$realif = get_real_interface($vip['interface']);
1699
	if (!does_interface_exist($realif)) {
1700
		file_notice("CARP", "Interface specified for the virtual IP address {$vip['subnet']} does not exist. Skipping this VIP.", "Firewall: Virtual IP", "");
1701
		return;
1702
	}
1703

    
1704
	if(is_ipaddrv4($vip['subnet'])) {
1705
		/* Ensure CARP IP really exists prior to loading up. */
1706
		$ww_subnet_ip = find_interface_ip($realif);
1707
		$ww_subnet_bits = find_interface_subnet($realif);
1708
		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'])) {
1709
			file_notice("CARP", "Sorry but we could not find a matching real interface subnet for the virtual IP address {$vip['subnet']}.", "Firewall: Virtual IP", "");
1710
			return;
1711
		}
1712
	}
1713
	if(is_ipaddrv6($vip['subnet'])) {
1714
		/* Ensure CARP IP really exists prior to loading up. */
1715
		$ww_subnet_ip = find_interface_ipv6($realif);
1716
		$ww_subnet_bits = find_interface_subnetv6($realif);
1717
		if (!ip_in_subnet($vip['subnet'], gen_subnetv6($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
1718
			file_notice("CARP", "Sorry but we could not find a matching real interface subnet for the virtual IPv6 address {$vip['subnet']}.", "Firewall: Virtual IP", "");
1719
			return;
1720
		}
1721
	}
1722

    
1723
	/* create the carp interface and setup */
1724
	if (does_interface_exist($vipif)) {
1725
		pfSense_interface_flags($vipif, -IFF_UP);
1726
	} else {
1727
		$carpif = pfSense_interface_create("carp");
1728
		pfSense_interface_rename($carpif, $vipif);
1729
		pfSense_ngctl_name("{$carpif}:", $vipif);
1730
	}
1731

    
1732
	/* invalidate interface cache */
1733
	get_interface_arr(true);
1734

    
1735
	if(is_ipaddrv4($vip['subnet'])) {
1736
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
1737
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$password}");
1738
	}
1739
	if(is_ipaddrv6($vip['subnet'])) {
1740
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
1741
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$password}");
1742
	}
1743

    
1744
	interfaces_bring_up($vipif);
1745
	
1746
	return $vipif;
1747
}
1748

    
1749
function interface_carpdev_configure(&$vip) {
1750
	global $g;
1751

    
1752
	if ($vip['mode'] != "carpdev-dhcp")
1753
		return;
1754

    
1755
	$vip_password = $vip['password'];
1756
	$vip_password = str_replace(" ", "", $vip_password);
1757
	if($vip['password'] != "")
1758
		$password = " pass \"" . $vip_password . "\"";
1759

    
1760
	log_error("Found carpdev interface {$vip['interface']} on top of interface {$interface}");
1761
	if (empty($vip['interface']))
1762
		return;
1763

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

    
1776
	if (does_interface_exist($vipif)) {
1777
		interface_bring_down($vipif);
1778
	} else {
1779
		$carpdevif = exec("/sbin/ifconfig carp create");
1780
		mwexec("/sbin/ifconfig {$carpdevif} name {$vipif}");
1781
		pfSense_ngctl_name("{$carpdevif}:", $vipif);
1782
	}
1783

    
1784
	mwexec("/sbin/ifconfig {$vipif} carpdev {$realif} vhid {$vip['vhid']} advskew {$vip['advskew']} {$password}");
1785
	interfaces_bring_up($vipif);
1786

    
1787
	/*
1788
	 * XXX: BIG HACK but carpdev needs ip services active
1789
	 *      before even starting something as dhclient.
1790
	 *      I do not know if this is a feature or a bug
1791
	 *      but better than track it make it work ;) .
1792
	 */
1793
	//$fakeiptouse = "10.254.254." . ($carp_instances_counter+1);
1794
	//$cmdchain->add("CarpDEV hack", "/sbin/ifconfig {$carpint} inet {$fakeiptouse}", false);
1795

    
1796
	/* generate dhclient_wan.conf */
1797
	$fd = fopen("{$g['varetc_path']}/dhclient_{$vipif}.conf", "w");
1798
	if ($fd) {
1799
		$dhclientconf = "";
1800

    
1801
		$dhclientconf .= <<<EOD
1802
interface "{$vipif}" {
1803
timeout 60;
1804
retry 1;
1805
select-timeout 0;
1806
initial-interval 1;
1807
script "/sbin/dhclient-script";
1808
}
1809

    
1810
EOD;
1811

    
1812
		fwrite($fd, $dhclientconf);
1813
		fclose($fd);
1814

    
1815
		/* fire up dhclient */
1816
		mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$vipif}.conf {$vipif} > {$g['tmp_path']}/{$vipif}_output > {$g['tmp_path']}/{$vipif}_error_output", false);
1817
	} else {
1818
		log_error("Error: cannot open dhclient_{$vipif}.conf in interfaces_carpdev_configure() for writing.\n");
1819
		mwexec("/sbin/dhclient -b {$vipif}");
1820
	}
1821

    
1822
	return $vipif;
1823
}
1824

    
1825
function interface_wireless_clone($realif, $wlcfg) {
1826
	global $config, $g;
1827
	/*   Check to see if interface has been cloned as of yet.  
1828
	 *   If it has not been cloned then go ahead and clone it.
1829
	 */
1830
	$needs_clone = false;
1831
	if(is_array($wlcfg['wireless']))
1832
		$wlcfg_mode = $wlcfg['wireless']['mode'];
1833
	else
1834
		$wlcfg_mode = $wlcfg['mode'];
1835
	switch($wlcfg_mode) {
1836
		 case "hostap":
1837
			$mode = "wlanmode hostap";
1838
			break;
1839
		 case "adhoc":
1840
			$mode = "wlanmode adhoc";
1841
			break;
1842
		 default:
1843
			$mode = "";
1844
			break;
1845
	}
1846
	$baseif = interface_get_wireless_base($wlcfg['if']);
1847
	if(does_interface_exist($realif)) {
1848
		exec("/sbin/ifconfig {$realif}", $output, $ret);
1849
		$ifconfig_str = implode($output);
1850
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
1851
			log_error("Interface {$realif} changed to hostap mode");
1852
			$needs_clone = true;
1853
		}
1854
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
1855
			log_error("Interface {$realif} changed to adhoc mode");
1856
			$needs_clone = true;
1857
		}
1858
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
1859
			log_error("Interface {$realif} changed to infrastructure mode");
1860
			$needs_clone = true;
1861
		}
1862
	} else {
1863
		$needs_clone = true;
1864
	}
1865

    
1866
	if($needs_clone == true) {
1867
		/* remove previous instance if it exists */
1868
		if(does_interface_exist($realif))
1869
			pfSense_interface_destroy($realif);
1870

    
1871
		log_error("Cloning new wireless interface {$realif}");
1872
		// Create the new wlan interface. FreeBSD returns the new interface name.
1873
		// example:  wlan2
1874
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
1875
		if($ret <> 0) {
1876
			log_error("Failed to clone interface {$baseif} with error code {$ret}, output {$out[0]}");
1877
			return false;
1878
		}
1879
		$newif = trim($out[0]);
1880
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
1881
		pfSense_interface_rename($newif, $realif);
1882
		// FIXME: not sure what ngctl is for. Doesn't work.
1883
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
1884
	}
1885
	return true;
1886
}
1887

    
1888
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
1889
	global $config, $g;
1890

    
1891
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
1892
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
1893
	                         'regdomain', 'regcountry', 'reglocation');
1894

    
1895
	if(!is_interface_wireless($ifcfg['if']))
1896
		return;
1897

    
1898
	$baseif = interface_get_wireless_base($ifcfg['if']);
1899

    
1900
	// Sync shared settings for assigned clones
1901
	$iflist = get_configured_interface_list(false, true);
1902
	foreach ($iflist as $if) {
1903
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
1904
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
1905
				foreach ($shared_settings as $setting) {
1906
					if ($sync_changes) {
1907
						if (isset($ifcfg['wireless'][$setting]))
1908
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
1909
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
1910
							unset($config['interfaces'][$if]['wireless'][$setting]);
1911
					} else {
1912
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
1913
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
1914
						else if (isset($ifcfg['wireless'][$setting]))
1915
							unset($ifcfg['wireless'][$setting]);
1916
					}
1917
				}
1918
				if (!$sync_changes)
1919
					break;
1920
			}
1921
		}
1922
	}
1923

    
1924
	// Read or write settings at shared area
1925
	if (isset($config['wireless']['interfaces'][$baseif])) {
1926
		foreach ($shared_settings as $setting) {
1927
			if ($sync_changes) {
1928
				if (isset($ifcfg['wireless'][$setting]))
1929
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
1930
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
1931
					unset($config['wireless']['interfaces'][$baseif][$setting]);
1932
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
1933
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
1934
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
1935
				else if (isset($ifcfg['wireless'][$setting]))
1936
					unset($ifcfg['wireless'][$setting]);
1937
			}
1938
		}
1939
	}
1940

    
1941
	// Sync the mode on the clone creation page with the configured mode on the interface
1942
	if (interface_is_wireless_clone($ifcfg['if'])) {
1943
		foreach ($config['wireless']['clone'] as &$clone) {
1944
			if ($clone['cloneif'] == $ifcfg['if']) {
1945
				if ($sync_changes) {
1946
					$clone['mode'] = $ifcfg['wireless']['mode'];
1947
				} else {
1948
					$ifcfg['wireless']['mode'] = $clone['mode'];
1949
				}
1950
				break;
1951
			}
1952
		}
1953
		unset($clone);
1954
	}
1955
}
1956

    
1957
function interface_wireless_configure($if, &$wl, &$wlcfg) {
1958
	global $config, $g;
1959

    
1960
	/*    open up a shell script that will be used to output the commands.
1961
	 *    since wireless is changing a lot, these series of commands are fragile
1962
     *    and will sometimes need to be verified by a operator by executing the command
1963
     *    and returning the output of the command to the developers for inspection.  please
1964
     *    do not change this routine from a shell script to individul exec commands.  -sullrich
1965
	 */
1966

    
1967
	// Remove script file
1968
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
1969

    
1970
	// Clone wireless nic if needed.
1971
	interface_wireless_clone($if, $wl);
1972

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

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

    
1980
	/* set values for /path/program */
1981
	$hostapd = "/usr/sbin/hostapd";
1982
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
1983
	$ifconfig = "/sbin/ifconfig";
1984
	$sysctl = "/sbin/sysctl";
1985
	$killall = "/usr/bin/killall";
1986

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

    
1989
	$wlcmd = array();
1990
	$wl_sysctl = array();
1991
	/* Make sure it's up */
1992
	$wlcmd[] = "up";
1993
	/* Set a/b/g standard */
1994
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
1995
	$wlcmd[] = "mode " . escapeshellarg($standard);
1996

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

    
2002
	/* Set ssid */
2003
	if($wlcfg['ssid'])
2004
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2005

    
2006
	/* Set 802.11g protection mode */
2007
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2008

    
2009
	/* set wireless channel value */
2010
	if(isset($wlcfg['channel'])) {
2011
		if($wlcfg['channel'] == "0") {
2012
			$wlcmd[] = "channel any";
2013
		} else {
2014
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2015
		}
2016
	}
2017

    
2018
	/* Set antenna diversity value */
2019
	if(isset($wlcfg['diversity']))
2020
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2021

    
2022
	/* Set txantenna value */
2023
	if(isset($wlcfg['txantenna']))
2024
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2025

    
2026
	/* Set rxantenna value */
2027
	if(isset($wlcfg['rxantenna']))
2028
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2029

    
2030
	/* set Distance value */
2031
	if($wlcfg['distance'])
2032
		$distance = escapeshellarg($wlcfg['distance']);
2033

    
2034
	/* Set wireless hostap mode */
2035
	if ($wlcfg['mode'] == "hostap") {
2036
		$wlcmd[] = "mediaopt hostap";
2037
	} else {
2038
		$wlcmd[] = "-mediaopt hostap";
2039
	}
2040

    
2041
	/* Set wireless adhoc mode */
2042
	if ($wlcfg['mode'] == "adhoc") {
2043
		$wlcmd[] = "mediaopt adhoc";
2044
	} else {
2045
		$wlcmd[] = "-mediaopt adhoc";
2046
	}
2047

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

    
2050
	/* handle hide ssid option */
2051
	if(isset($wlcfg['hidessid']['enable'])) {
2052
		$wlcmd[] = "hidessid";
2053
	} else {
2054
		$wlcmd[] = "-hidessid";
2055
	}
2056

    
2057
	/* handle pureg (802.11g) only option */
2058
	if(isset($wlcfg['pureg']['enable'])) {
2059
		$wlcmd[] = "mode 11g pureg";
2060
	} else {
2061
		$wlcmd[] = "-pureg";
2062
	}
2063

    
2064
	/* handle puren (802.11n) only option */
2065
	if(isset($wlcfg['puren']['enable'])) {
2066
		$wlcmd[] = "puren";
2067
	} else {
2068
		$wlcmd[] = "-puren";
2069
	}
2070

    
2071
	/* enable apbridge option */
2072
	if(isset($wlcfg['apbridge']['enable'])) {
2073
		$wlcmd[] = "apbridge";
2074
	} else {
2075
		$wlcmd[] = "-apbridge";
2076
	}
2077

    
2078
	/* handle turbo option */
2079
	if(isset($wlcfg['turbo']['enable'])) {
2080
		$wlcmd[] = "mediaopt turbo";
2081
	} else {
2082
		$wlcmd[] = "-mediaopt turbo";
2083
	}
2084

    
2085
	/* handle txpower setting */
2086
	/* if($wlcfg['txpower'] <> "")
2087
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2088
	*/
2089
	/* handle wme option */
2090
	if(isset($wlcfg['wme']['enable'])) {
2091
		$wlcmd[] = "wme";
2092
	} else {
2093
		$wlcmd[] = "-wme";
2094
	}
2095

    
2096
	/* set up wep if enabled */
2097
	$wepset = "";
2098
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2099
		switch($wlcfg['wpa']['auth_algs']) {
2100
			case "1":
2101
				$wepset .= "authmode open wepmode on ";
2102
				break;
2103
			case "2":
2104
				$wepset .= "authmode shared wepmode on ";
2105
				break;
2106
			case "3":
2107
				$wepset .= "authmode mixed wepmode on ";
2108
		}
2109
		$i = 1;
2110
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2111
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2112
			if (isset($wepkey['txkey'])) {
2113
				$wlcmd[] = "weptxkey {$i} ";
2114
			}
2115
			$i++;
2116
		}
2117
		$wlcmd[] = $wepset;
2118
	} else {
2119
		$wlcmd[] = "authmode open wepmode off ";
2120
	}
2121

    
2122
	mwexec(kill_hostapd("{$if}"));
2123
	mwexec(kill_wpasupplicant("{$if}"));
2124

    
2125
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2126
	conf_mount_rw();
2127

    
2128
	switch ($wlcfg['mode']) {
2129
		case 'bss':
2130
			if (isset($wlcfg['wpa']['enable'])) {
2131
				$wpa .= <<<EOD
2132
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2133
ctrl_interface_group=0
2134
ap_scan=1
2135
#fast_reauth=1
2136
network={
2137
ssid="{$wlcfg['ssid']}"
2138
scan_ssid=1
2139
priority=5
2140
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2141
psk="{$wlcfg['wpa']['passphrase']}"
2142
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2143
group={$wlcfg['wpa']['wpa_pairwise']}
2144
}
2145
EOD;
2146

    
2147
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2148
				fwrite($fd, "{$wpa}");
2149
				fclose($fd);
2150
			}
2151
			break;
2152
		case 'hostap':
2153
			if($wlcfg['wpa']['passphrase']) 
2154
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2155
			else 
2156
				$wpa_passphrase = "";
2157
			if (isset($wlcfg['wpa']['enable'])) {
2158
				$wpa .= <<<EOD
2159
interface={$if}
2160
driver=bsd
2161
logger_syslog=-1
2162
logger_syslog_level=0
2163
logger_stdout=-1
2164
logger_stdout_level=0
2165
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2166
ctrl_interface={$g['varrun_path']}/hostapd
2167
ctrl_interface_group=wheel
2168
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2169
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2170
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2171
ssid={$wlcfg['ssid']}
2172
debug={$wlcfg['wpa']['debug_mode']}
2173
auth_algs={$wlcfg['wpa']['auth_algs']}
2174
wpa={$wlcfg['wpa']['wpa_mode']}
2175
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2176
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2177
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2178
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2179
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2180
{$wpa_passphrase}
2181

    
2182
EOD;
2183

    
2184
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2185
	$wpa .= <<<EOD
2186
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2187
rsn_preauth=1
2188
rsn_preauth_interfaces={$if}
2189

    
2190
EOD;
2191

    
2192
}
2193
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2194
					$auth_server_port = "1812";
2195
					if($wlcfg['auth_server_port']) 
2196
						$auth_server_port = $wlcfg['auth_server_port'];
2197
					$wpa .= <<<EOD
2198

    
2199
ieee8021x=1
2200
auth_server_addr={$wlcfg['auth_server_addr']}
2201
auth_server_port={$auth_server_port}
2202
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2203

    
2204
EOD;
2205
				} else {
2206
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2207
				}
2208

    
2209
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2210
				fwrite($fd, "{$wpa}");
2211
				fclose($fd);
2212

    
2213
			}
2214
			break;
2215
	}
2216

    
2217
	/*
2218
	 *    all variables are set, lets start up everything
2219
	 */
2220

    
2221
	$baseif = interface_get_wireless_base($if);
2222
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2223
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2224

    
2225
	/* set sysctls for the wireless interface */
2226
	if (!empty($wl_sysctl)) {
2227
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2228
		foreach ($wl_sysctl as $wl_sysctl_line) {
2229
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2230
		}
2231
	}
2232

    
2233
	/* set ack timers according to users preference (if he/she has any) */
2234
	if($distance) {
2235
		fwrite($fd_set, "# Enable ATH distance settings\n");
2236
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2237
	}
2238

    
2239
	if (isset($wlcfg['wpa']['enable'])) {
2240
		if ($wlcfg['mode'] == "bss") {
2241
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2242
		}
2243
		if ($wlcfg['mode'] == "hostap") {
2244
			fwrite($fd_set, "{$hostapd} -B {$g['varetc_path']}/hostapd_{$if}.conf\n");
2245
		}
2246
	}
2247

    
2248
	fclose($fd_set);
2249
	conf_mount_ro();
2250

    
2251
	/* Making sure regulatory settings have actually changed
2252
	 * before applying, because changing them requires bringing
2253
	 * down all wireless networks on the interface. */
2254
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2255
	$ifconfig_str = implode($output);
2256
	unset($output);
2257
	$reg_changing = false;
2258

    
2259
	/* special case for the debug country code */
2260
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2261
		$reg_changing = true;
2262
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2263
		$reg_changing = true;
2264
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2265
		$reg_changing = true;
2266
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2267
		$reg_changing = true;
2268
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2269
		$reg_changing = true;
2270

    
2271
	if ($reg_changing) {
2272
		/* set regulatory domain */
2273
		if($wlcfg['regdomain'])
2274
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2275

    
2276
		/* set country */
2277
		if($wlcfg['regcountry'])
2278
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2279

    
2280
		/* set location */
2281
		if($wlcfg['reglocation'])
2282
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2283

    
2284
		$wlregcmd_args = implode(" ", $wlregcmd);
2285

    
2286
		/* build a complete list of the wireless clones for this interface */
2287
		$clone_list = array();
2288
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2289
			$clone_list[] = interface_get_wireless_clone($baseif);
2290
		if (is_array($config['wireless']['clone'])) {
2291
			foreach ($config['wireless']['clone'] as $clone) {
2292
				if ($clone['if'] == $baseif)
2293
					$clone_list[] = $clone['cloneif'];
2294
			}
2295
		}
2296

    
2297
		/* find which clones are up and bring them down */
2298
		$clones_up = array();
2299
		foreach ($clone_list as $clone_if) {
2300
			$clone_status = pfSense_get_interface_addresses($clone_if);
2301
			if ($clone_status['status'] == 'up') {
2302
				$clones_up[] = $clone_if;
2303
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2304
			}
2305
		}
2306

    
2307
		/* apply the regulatory settings */
2308
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2309

    
2310
		/* bring the clones back up that were previously up */
2311
		foreach ($clones_up as $clone_if) {
2312
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2313

    
2314
			/*
2315
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2316
			 * is in infrastructure mode, and WPA is enabled.
2317
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2318
			 */
2319
			if ($clone_if != $if) {
2320
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2321
				if ( !empty($friendly_if)
2322
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2323
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2324
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2325
				}
2326
			}
2327
		}
2328
	}
2329

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

    
2334
	/* configure wireless */
2335
	$wlcmd_args = implode(" ", $wlcmd);
2336
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2337

    
2338
	
2339
	sleep(1);
2340
	/* execute hostapd and wpa_supplicant if required in shell */
2341
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2342

    
2343
	return 0;
2344

    
2345
}
2346

    
2347
function kill_hostapd($interface) {
2348
	return "/bin/pkill -f \"hostapd .*{$interface}\"\n";
2349
}
2350

    
2351
function kill_wpasupplicant($interface) {
2352
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\"\n";
2353
}
2354

    
2355
function find_dhclient_process($interface) {
2356
	if ($interface)
2357
		$pid = `/bin/pgrep -xf "dhclient: {$interface}"`;
2358
	else
2359
		$pid = 0;
2360

    
2361
	return $pid;
2362
}
2363

    
2364
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2365
	global $config, $g;
2366
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2367
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2368

    
2369
	$wancfg = $config['interfaces'][$interface];
2370

    
2371
	$realif = get_real_interface($interface);
2372

    
2373
	if (!$g['booting']) {
2374
		/* remove all IPv4 addresses */
2375
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0);
2376
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -alias", true) == 0);
2377

    
2378
		switch ($wancfg['ipaddr']) {
2379
			case 'pppoe':
2380
			case 'l2tp':
2381
			case 'pptp':
2382
			case 'ppp':
2383
				interface_bring_down($interface, true);
2384
				break;
2385
			default:
2386
				interface_bring_down($interface);
2387
				break;
2388
		}
2389
	}
2390

    
2391
	/* wireless configuration? */
2392
	if (is_array($wancfg['wireless']))
2393
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2394

    
2395
	if ($wancfg['spoofmac']) {
2396
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) .
2397
			" link " . escapeshellarg($wancfg['spoofmac']));
2398

    
2399
                /*
2400
                 * All vlans need to spoof their parent mac address, too.  see
2401
                 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2402
                 */
2403
                if (is_array($config['vlans']['vlan'])) {
2404
                        foreach ($config['vlans']['vlan'] as $vlan) {
2405
                                if ($vlan['if'] == $realif)
2406
                                        mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2407
                                                " link " . escapeshellarg($wancfg['spoofmac']));
2408
                        }
2409
                }
2410
	}  else {
2411
		$mac = get_interface_mac(get_real_interface($wancfg['if']));
2412
		if($mac == "ff:ff:ff:ff:ff:ff") {
2413
			/*   this is not a valid mac address.  generate a
2414
			 *   temporary mac address so the machine can get online.
2415
			 */
2416
			echo "Generating new MAC address.";
2417
			$random_mac = generate_random_mac_address();
2418
			mwexec("/sbin/ifconfig " . escapeshellarg(get_real_interface($wancfg['if'])) .
2419
				" link " . escapeshellarg($random_mac));
2420
			$wancfg['spoofmac'] = $random_mac;
2421
			write_config();
2422
			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");
2423
		}
2424
	}
2425

    
2426
	/* media */
2427
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2428
		$cmd = "/sbin/ifconfig " . escapeshellarg(get_real_interface($wancfg['if']));
2429
		if ($wancfg['media'])
2430
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2431
		if ($wancfg['mediaopt'])
2432
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2433
		mwexec($cmd);
2434
	}
2435
	if (!empty($wancfg['mtu']))
2436
		pfSense_interface_mtu($realif, $wancfg['mtu']);
2437

    
2438
	$options = pfSense_get_interface_addresses($realif);
2439
	if (is_array($options) && isset($options['caps']['polling'])) {
2440
		if (isset($config['system']['polling']))
2441
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2442
		else
2443
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2444
	}
2445

    
2446
	/* skip vlans for checksumming and polling */
2447
        if (!stristr($realif, "vlan") && is_array($options)) {
2448
		$flags = 0;
2449
		if(isset($config['system']['disablechecksumoffloading'])) {
2450
			if (isset($options['encaps']['txcsum']))
2451
				$flags |= IFCAP_TXCSUM;
2452
			if (isset($options['encaps']['rxcsum']))
2453
				$flags |= IFCAP_RXCSUM;
2454
        	} else {
2455
 			if (!isset($options['caps']['txcsum']))
2456
				$flags |= IFCAP_TXCSUM;
2457
			if (!isset($options['caps']['rxcsum']))
2458
				$flags |= IFCAP_RXCSUM;
2459
        	}
2460

    
2461
        	if(isset($config['system']['disablesegmentationoffloading'])) {
2462
                	if (isset($options['encaps']['tso4']))
2463
				$flags |= IFCAP_TSO;
2464
                	if (isset($options['encaps']['tso6']))
2465
				$flags |= IFCAP_TSO;
2466
        	} else {
2467
                	if (!isset($options['caps']['tso4']))
2468
				$flags |= IFCAP_TSO;
2469
                	if (!isset($options['caps']['tso6']))
2470
				$flags |= IFCAP_TSO;
2471
        	}
2472

    
2473
        	if(isset($config['system']['disablelargereceiveoffloading'])) {
2474
                	if (isset($options['encaps']['lro']))
2475
				$flags |= IFCAP_LRO;
2476
        	} else {
2477
                	if (!isset($options['caps']['lro']))
2478
				$flags |= IFCAP_LRO;
2479
        	}
2480

    
2481
        	/* if the NIC supports polling *AND* it is enabled in the GUI */
2482
        	if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2483
			$flags |= IFCAP_POLLING;
2484
		}
2485
               	pfSense_interface_capabilities($realif, -$flags);
2486
	}
2487

    
2488
	/* invalidate interface/ip/sn cache */
2489
	get_interface_arr(true);
2490
	unset($interface_ip_arr_cache[$realif]);
2491
	unset($interface_sn_arr_cache[$realif]);
2492
	unset($interface_ipv6_arr_cache[$realif]);
2493
	unset($interface_snv6_arr_cache[$realif]);
2494

    
2495
	switch ($wancfg['ipaddr']) {
2496
		case 'carpdev-dhcp':
2497
			interface_carpdev_dhcp_configure($interface);
2498
			break;
2499
		case 'dhcp':
2500
			interface_dhcp_configure($interface);
2501
			break;
2502
		case 'pppoe':
2503
		case 'l2tp':
2504
		case 'pptp':
2505
		case 'ppp':
2506
			interface_ppps_configure($interface);
2507
			break;
2508
		default:
2509
			if ($wancfg['ipaddr'] <> "" && $wancfg['subnet'] <> "") {
2510
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2511
			} else if (substr($realif, 0, 3) == "gre") {
2512
				if (is_array($config['gres']['gre'])) {
2513
					foreach ($config['gres']['gre'] as $gre)
2514
						if ($gre['greif'] == $realif)
2515
							interface_gre_configure($gre);
2516
				}
2517
			} else if (substr($realif, 0, 3) == "gif") {
2518
				 if (is_array($config['gifs']['gif'])) {
2519
					foreach ($config['gifs']['gif'] as $gif)
2520
						if($gif['gifif'] == $interface)
2521
							interface_gif_configure($gif);
2522
				}
2523
			} else if (substr($realif, 0, 4) == "ovpn") {
2524
				/* XXX: Should be done anything?! */
2525
			}
2526
			break;
2527
	}
2528

    
2529
	switch ($wancfg['ipaddrv6']) {
2530
		case 'dhcpv6':
2531
			interface_dhcpv6_configure($interface);
2532
			break;
2533
		default:
2534
			if ($wancfg['ipaddrv6'] <> "" && $wancfg['subnetv6'] <> "") {
2535
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
2536
				mwexec("/sbin/ifconfig {$realif} inet6 {$wancfg['ipaddrv6']} prefixlen {$wancfg['subnetv6']} ");
2537
			}
2538
			break;
2539
	}
2540

    
2541
	if(does_interface_exist($wancfg['if']))
2542
		interfaces_bring_up($wancfg['if']);
2543
 	
2544
	if (!$g['booting']) {
2545
		interface_reload_carps($realif);
2546

    
2547
		unset($gre);
2548
		$gre = link_interface_to_gre($interface);
2549
		if (!empty($gre))
2550
			interface_gre_configure($gre);
2551

    
2552
		unset($gif);
2553
		$gif = link_interface_to_gif($interface);
2554
		if (!empty($gif))
2555
                       	interface_gif_configure($gif);
2556

    
2557
		if ($linkupevent == false) {
2558
			unset($bridgetmp);
2559
			$bridgetmp = link_interface_to_bridge($interface);
2560
			if (!empty($bridgetmp))
2561
				interface_bridge_add_member($bridgetmp, $realif);
2562
		}
2563

    
2564
		link_interface_to_vips($interface, "update");
2565

    
2566
		$grouptmp = link_interface_to_group($interface);
2567
		if (!empty($grouptmp))
2568
			interface_group_add_member($realif, $grouptmp);
2569

    
2570
		if ($interface == "lan")
2571
			/* make new hosts file */
2572
			system_hosts_generate();
2573

    
2574
		if ($reloadall == true) {
2575

    
2576
			/* reconfigure static routes (kernel may have deleted them) */
2577
			system_routing_configure($interface);
2578

    
2579
			/* reload ipsec tunnels */
2580
			vpn_ipsec_configure();
2581

    
2582
			/* restart dnsmasq */
2583
			services_dnsmasq_configure();
2584

    
2585
			/* update dyndns */
2586
			services_dyndns_configure($interface);
2587

    
2588
			/* force DNS update */
2589
			services_dnsupdate_process($interface);
2590

    
2591
			/* reload captive portal */
2592
			captiveportal_init_rules();
2593

    
2594
			/* set the reload filter dity flag */
2595
			filter_configure();
2596
		}
2597
	}
2598

    
2599
	return 0;
2600
}
2601

    
2602
function interface_carpdev_dhcp_configure($interface = "wan") {
2603
	global $config, $g;
2604

    
2605
	$wancfg = $config['interfaces'][$interface];
2606
	$wanif = $wancfg['if'];
2607
	/* bring wan interface up before starting dhclient */
2608
	if($wanif)
2609
		interfaces_bring_up($wanif);
2610
	else 
2611
		log_error("Could not bring wanif up in terface_carpdev_dhcp_configure()");
2612

    
2613
	return 0;
2614
}
2615

    
2616
function interface_dhcp_configure($interface = "wan") {
2617
	global $config, $g;
2618

    
2619
	$wancfg = $config['interfaces'][$interface];
2620
	if (empty($wancfg))
2621
		$wancfg = array();
2622

    
2623
	/* generate dhclient_wan.conf */
2624
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
2625
	if (!$fd) {
2626
		printf("Error: cannot open dhclient_{$interface}.conf in interfaces_wan_dhcp_configure() for writing.\n");
2627
		return 1;
2628
	}
2629

    
2630
	if ($wancfg['dhcphostname']) {
2631
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
2632
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
2633
	} else {
2634
		$dhclientconf_hostname = "";
2635
	}
2636

    
2637
	$wanif = get_real_interface($interface);
2638
	if (empty($wanif)) {
2639
		log_error("Invalid interface \"{$interface}\" in interface_dhcp_configure()");
2640
		return 0;
2641
	}
2642
 	$dhclientconf = "";
2643
	
2644
	$dhclientconf .= <<<EOD
2645
interface "{$wanif}" {
2646
timeout 60;
2647
retry 1;
2648
select-timeout 0;
2649
initial-interval 1;
2650
	{$dhclientconf_hostname}
2651
	script "/sbin/dhclient-script";
2652
}
2653

    
2654
EOD;
2655

    
2656
if(is_ipaddr($wancfg['alias-address'])) {
2657
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
2658
	$dhclientconf .= <<<EOD
2659
alias {
2660
	interface  "{$wanif}";
2661
	fixed-address {$wancfg['alias-address']};
2662
	option subnet-mask {$subnetmask};
2663
}
2664

    
2665
EOD;
2666
}
2667
	fwrite($fd, $dhclientconf);
2668
	fclose($fd);
2669

    
2670
	/* bring wan interface up before starting dhclient */
2671
	if($wanif)
2672
		interfaces_bring_up($wanif);
2673
	else 
2674
		log_error("Could not bring up {$wanif} interface in interface_dhcp_configure()");
2675

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

    
2679
	return 0;
2680
}
2681

    
2682
function interfaces_group_setup() {
2683
	global $config;
2684

    
2685
	if (!is_array($config['ifgroups']['ifgroupentry']))
2686
		return;
2687

    
2688
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
2689
		interface_group_setup($groupar);
2690

    
2691
	return;
2692
}
2693

    
2694
function interface_group_setup(&$groupname /* The parameter is an array */) {
2695
	global $config;
2696

    
2697
	if (!is_array($groupname))
2698
		return;
2699
	$members = explode(" ", $groupname['members']);
2700
	foreach($members as $ifs) {
2701
		$realif = get_real_interface($ifs);
2702
		if ($realif)
2703
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
2704
	}
2705

    
2706
	return;
2707
}
2708

    
2709
function interface_group_add_member($interface, $groupname) {
2710
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
2711
}
2712
 
2713
/* COMPAT Function */
2714
function convert_friendly_interface_to_real_interface_name($interface) {
2715
	return get_real_interface($interface);
2716
}
2717

    
2718
/* COMPAT Function */
2719
function get_real_wan_interface($interface = "wan") {
2720
	return get_real_interface($interface);
2721
}
2722

    
2723
/* COMPAT Function */
2724
function get_current_wan_address($interface = "wan") {
2725
	return get_interface_ip($interface);
2726
}
2727

    
2728
/*
2729
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
2730
 */
2731
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
2732
        global $config;
2733

    
2734
	if (stristr($interface, "vip")) {
2735
                $index = intval(substr($interface, 3));
2736
                foreach ($config['virtualip']['vip'] as $counter => $vip) {
2737
                        if ($vip['mode'] == "carpdev-dhcp" || $vip['mode'] == "carp")  {
2738
                                if ($index == $counter)
2739
                                        return $vip['interface'];
2740
                        }
2741
                }
2742
        }
2743

    
2744
        /* XXX: For speed reasons reference directly the interface array */
2745
	$ifdescrs = &$config['interfaces'];
2746
        //$ifdescrs = get_configured_interface_list(false, true);
2747

    
2748
        foreach ($ifdescrs as $if => $ifname) {
2749
                if ($config['interfaces'][$if]['if'] == $interface)
2750
                        return $if;
2751

    
2752
                if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
2753
                        return $if;
2754

    
2755
                $int = interface_translate_type_to_real($if);
2756
                if ($int == $interface)
2757
                        return $ifname;
2758
        }
2759
        return NULL;
2760
}
2761

    
2762
/* attempt to resolve interface to friendly descr */
2763
function convert_friendly_interface_to_friendly_descr($interface) {
2764
        global $config;
2765

    
2766
        switch ($interface) {
2767
                case "l2tp":
2768
                                $ifdesc = "L2TP";
2769
                                break;
2770
                case "pptp":
2771
                                $ifdesc = "PPTP";
2772
                                break;
2773
                case "pppoe":
2774
                                $ifdesc = "PPPoE";
2775
                                break;
2776
                case "openvpn":
2777
                                $ifdesc = "OpenVPN";
2778
                                break;
2779
                case "enc0":
2780
                        case "ipsec":
2781
                                $ifdesc = "IPsec";
2782
                                break;
2783
        default:
2784
                if (isset($config['interfaces'][$interface])) {
2785
                        if (empty($config['interfaces'][$interface]['descr']))
2786
                                $ifdesc = strtoupper($interface);
2787
                        else
2788
                                $ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
2789
			break;
2790
		}
2791
                /* if list */
2792
                $ifdescrs = get_configured_interface_with_descr(false, true);
2793
                foreach ($ifdescrs as $if => $ifname) {
2794
                                if ($if == $interface || $ifname == $interface)
2795
                                        return $ifname;
2796
                }
2797
                break;
2798
        }
2799

    
2800
        return $ifdesc;
2801
}
2802

    
2803
function convert_real_interface_to_friendly_descr($interface) {
2804
        global $config;
2805

    
2806
        $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
2807

    
2808
        if ($ifdesc) {
2809
                $iflist = get_configured_interface_with_descr(false, true);
2810
                return $iflist[$ifdesc];
2811
        }
2812

    
2813
        return $interface;
2814
}
2815

    
2816
/*
2817
 *  interface_translate_type_to_real($interface):
2818
 *              returns the real hardware interface name for a friendly interface.  ie: wan
2819
 */
2820
function interface_translate_type_to_real($interface) {
2821
        global $config;
2822

    
2823
        if ($config['interfaces'][$interface]['if'] <> "")
2824
                return $config['interfaces'][$interface]['if'];
2825
        else
2826
		return $interface;
2827
}
2828

    
2829
function interface_is_wireless_clone($wlif) {
2830
	if(!stristr($wlif, "_wlan")) {
2831
		return false;
2832
	} else {
2833
		return true;
2834
	}
2835
}
2836

    
2837
function interface_get_wireless_base($wlif) {
2838
	if(!stristr($wlif, "_wlan")) {
2839
		return $wlif;
2840
	} else {
2841
		return substr($wlif, 0, stripos($wlif, "_wlan"));
2842
	}
2843
}
2844

    
2845
function interface_get_wireless_clone($wlif) {
2846
	if(!stristr($wlif, "_wlan")) {
2847
		return $wlif . "_wlan0";
2848
	} else {
2849
		return $wlif;
2850
	}
2851
}
2852

    
2853
function get_real_interface($interface = "wan") {
2854
    global $config;
2855

    
2856
	$wanif = NULL;
2857

    
2858
	switch ($interface) {
2859
	case "l2tp":
2860
		$wanif = "l2tp";
2861
		break;
2862
	case "pptp":
2863
		$wanif = "pptp";
2864
		break;
2865
	case "pppoe":
2866
		$wanif = "pppoe";
2867
		break;
2868
	case "openvpn":
2869
		$wanif = "openvpn";
2870
		break;
2871
	case "ipsec":
2872
	case "enc0":
2873
		$wanif = "enc0";
2874
		break;
2875
	case "ppp":
2876
		$wanif = "ppp";
2877
		break;
2878
	default:
2879
		// If a real interface was alread passed simply
2880
		// pass the real interface back.  This encourages
2881
		// the usage of this function in more cases so that
2882
		// we can combine logic for more flexibility.
2883
		if(does_interface_exist($interface)) {
2884
			$wanif = $interface;
2885
			break;
2886
		}
2887
		if (empty($config['interfaces'][$interface]))
2888
			break;
2889

    
2890
		$cfg = &$config['interfaces'][$interface];
2891

    
2892
		// Wireless cloned NIC support (FreeBSD 8+)
2893
		// interface name format: $parentnic_wlanparentnic#
2894
		// example: ath0_wlan0
2895
		if (is_interface_wireless($cfg['if'])) {
2896
			$wanif = interface_get_wireless_clone($cfg['if']);
2897
			break;
2898
		}
2899
		/*
2900
		if (empty($cfg['if'])) {
2901
			$wancfg = $cfg['if'];
2902
			break;
2903
		}
2904
		*/
2905

    
2906
		switch ($cfg['ipaddr']) {
2907
			case "carpdev-dhcp":
2908
				$viparr = &$config['virtualip']['vip'];
2909
				if(is_array($viparr))
2910
				foreach ($viparr as $counter => $vip) {
2911
					if ($vip['mode'] == "carpdev-dhcp") {
2912
						if($vip['interface'] == $interface) {
2913
							$wanif = "carp{$counter}";
2914
							break;
2915
						}
2916
					}
2917
				}
2918
				break;
2919
			case "pppoe": 
2920
			case "pptp": 
2921
			case "l2tp": 
2922
			case "ppp":
2923
				$wanif = $cfg['if'];
2924
				break;
2925
			default:
2926
				$wanif = $cfg['if'];
2927
				break;
2928
		}
2929
		break;
2930
	}
2931

    
2932
    return $wanif;
2933
}
2934

    
2935
/* Guess the physical interface by providing a IP address */
2936
function guess_interface_from_ip($ipaddress) {
2937
	if(! is_ipaddr($ipaddress)) {
2938
		return false;
2939
	}
2940
	/* create a route table we can search */
2941
	exec("netstat -rnWf inet", $output, $ret);
2942
	foreach($output as $line) {
2943
		if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
2944
			$fields = preg_split("/[ ]+/", $line);
2945
			if(ip_in_subnet($ipaddress, $fields[0])) {
2946
				return $fields[6];
2947
			}
2948
		}
2949
	}
2950
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
2951
	if(empty($ret)) {
2952
        	return false;
2953
	}
2954
	return $ret;
2955
}
2956

    
2957
/*
2958
 * find_ip_interface($ip): return the interface where an ip is defined
2959
 */
2960
function find_ip_interface($ip)
2961
{
2962
        /* if list */
2963
        $ifdescrs = get_configured_interface_list();
2964

    
2965
        foreach ($ifdescrs as $ifdescr => $ifname) {
2966
		if ($ip == get_interface_ip($ifname)) {
2967
                	$int = get_real_interface($ifname);
2968
			return $int;
2969
		}
2970
        }
2971
        return false;
2972
}
2973

    
2974
/*
2975
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
2976
 */
2977
function find_number_of_created_carp_interfaces() {
2978
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
2979
}
2980

    
2981
function get_all_carp_interfaces() {
2982
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
2983
	$ints = explode(" ", $ints);
2984
	return $ints;
2985
}
2986

    
2987
/*
2988
 * find_carp_interface($ip): return the carp interface where an ip is defined
2989
 */
2990
function find_carp_interface($ip) {
2991
	global $config;
2992
	if (is_array($config['virtualip']['vip'])) {
2993
		foreach ($config['virtualip']['vip'] as $vip) {
2994
			if ($vip['mode'] == "carp" || $vip['mode'] == "carpdev") {
2995
				if(is_ipaddrv4($ip)) {
2996
					$carp_ip = get_interface_ip($vip['interface']);
2997
				}
2998
				if(is_ipaddrv6($ip)) {
2999
					$carp_ip = get_interface_ipv6($vip['interface']);
3000
				}
3001
				exec("/sbin/ifconfig", $output, $return);
3002
				foreach($output as $line) {
3003
					$elements = preg_split("/[ ]+/i", $line);
3004
					if(strstr($elements[0], "vip"))
3005
						$curif = str_replace(":", "", $elements[0]);
3006
					if(stristr($line, $ip)) {
3007
						$if = $curif;
3008
						continue;
3009
					}
3010
				}
3011
				if ($if)
3012
					return $if;
3013
			}
3014
		}
3015
	}
3016
}
3017

    
3018
function link_carp_interface_to_parent($interface) {
3019
        global $config;
3020

    
3021
        if ($interface == "")
3022
                return;
3023

    
3024
        $carp_ip = get_interface_ip($interface);
3025
        if (!is_ipaddr($carp_ip))
3026
                return;
3027

    
3028
        /* if list */
3029
        $ifdescrs = get_configured_interface_list();
3030
        foreach ($ifdescrs as $ifdescr => $ifname) {
3031
                $interfaceip = get_interface_ip($ifname);
3032
                $subnet_bits = get_interface_subnet($ifname);
3033
                $subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3034
                if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3035
                        return $ifname;
3036
        }
3037

    
3038
        return "";
3039
}
3040

    
3041
/****f* interfaces/link_ip_to_carp_interface
3042
 * NAME
3043
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3044
 * INPUTS
3045
 *   $ip
3046
 * RESULT
3047
 *   $carp_ints
3048
 ******/
3049
function link_ip_to_carp_interface($ip) {
3050
        global $config;
3051

    
3052
        if (!is_ipaddr($ip))
3053
                return;
3054

    
3055
        $carp_ints = "";
3056
        if (is_array($config['virtualip']['vip'])) {
3057
		$first = 0;
3058
		$carp_int = array();
3059
                foreach ($config['virtualip']['vip'] as $vip) {
3060
                        if ($vip['mode'] == "carp" || $vip['mode'] == "carpdev") {
3061
                                $carp_ip = $vip['subnet'];
3062
                                $carp_sn = $vip['subnet_bits'];
3063
                                $carp_nw = gen_subnet($carp_ip, $carp_sn);
3064
                                if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}"))
3065
					$carp_int[] = "vip{$vip['vhid']}";
3066
                        }
3067
                }
3068
		if (!empty($carp_int))
3069
			$carp_ints = implode(" ", array_unique($carp_int));
3070
        }
3071

    
3072
        return $carp_ints;
3073
}
3074

    
3075
function link_interface_to_vlans($int, $action = "") {
3076
	global $config;
3077

    
3078
	if (empty($int))
3079
		return;
3080

    
3081
	if (is_array($config['vlans']['vlan'])) {
3082
                foreach ($config['vlans']['vlan'] as $vlan) {
3083
			if ($int == $vlan['if']) {
3084
				if ($action == "update") {
3085
					interfaces_bring_up($int);
3086
				} else if ($action == "")
3087
					return $vlan;
3088
			}
3089
		}
3090
	}
3091
}
3092

    
3093
function link_interface_to_vips($int, $action = "") {
3094
        global $config;
3095

    
3096
        if (is_array($config['virtualip']['vip']))
3097
                foreach ($config['virtualip']['vip'] as $vip)
3098
                        if ($int == $vip['interface']) {
3099
				if ($action == "update")
3100
					interfaces_vips_configure($int);
3101
				else
3102
                                	return $vip;
3103
			}
3104
}
3105

    
3106
/****f* interfaces/link_interface_to_bridge
3107
 * NAME
3108
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3109
 * INPUTS
3110
 *   $ip
3111
 * RESULT
3112
 *   bridge[0-99]
3113
 ******/
3114
function link_interface_to_bridge($int) {
3115
        global $config;
3116

    
3117
        if (is_array($config['bridges']['bridged'])) {
3118
                foreach ($config['bridges']['bridged'] as $bridge) {
3119
			if (in_array($int, explode(',', $bridge['members'])))
3120
                                return "{$bridge['bridgeif']}";
3121
		}
3122
	}
3123
}
3124

    
3125
function link_interface_to_group($int) {
3126
        global $config;
3127

    
3128
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3129
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3130
			if (in_array($int, explode(" ", $groupname['members'])))
3131
                                return "{$group['ifname']}";
3132
		}
3133
	}
3134
}
3135

    
3136
function link_interface_to_gre($interface) {
3137
        global $config;
3138

    
3139
        if (is_array($config['gres']['gre']))
3140
                foreach ($config['gres']['gre'] as $gre)
3141
                        if($gre['if'] == $interface)
3142
                                return $gre;
3143
}
3144

    
3145
function link_interface_to_gif($interface) {
3146
        global $config;
3147

    
3148
        if (is_array($config['gifs']['gif']))
3149
                foreach ($config['gifs']['gif'] as $gif)
3150
                        if($gif['if'] == $interface)
3151
                                return $gif;
3152
}
3153

    
3154
/*
3155
 * find_interface_ip($interface): return the interface ip (first found)
3156
 */
3157
function find_interface_ip($interface, $flush = false)
3158
{
3159
	global $interface_ip_arr_cache;
3160
	global $interface_sn_arr_cache;
3161

    
3162
	$interface = str_replace("\n", "", $interface);
3163
	
3164
	if (!does_interface_exist($interface))
3165
		return;
3166

    
3167
	/* Setup IP cache */
3168
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
3169
		$ifinfo = pfSense_get_interface_addresses($interface);
3170
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
3171
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
3172
	}
3173

    
3174
	return $interface_ip_arr_cache[$interface];
3175
}
3176

    
3177
/*
3178
 * find_interface_ipv6($interface): return the interface ip (first found)
3179
 */
3180
function find_interface_ipv6($interface, $flush = false)
3181
{
3182
	global $interface_ipv6_arr_cache;
3183
	global $interface_snv6_arr_cache;
3184
	global $config;
3185
	
3186
	$interface = str_replace("\n", "", $interface);
3187
	
3188
	if (!does_interface_exist($interface))
3189
		return;
3190

    
3191
	/* Setup IP cache */
3192
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
3193
		$ifinfo = pfSense_get_interface_addresses($interface);
3194
		exec("/sbin/ifconfig {$interface} inet6", $output);
3195
		foreach($output as $line) {
3196
			if(preg_match("/inet6/", $line)) {
3197
				$parts = explode(" ", $line);
3198
				if(! stristr("fe80::", $parts[1])) {
3199
					$ifinfo['ipaddrv6'] = $parts[1];
3200
					$ifinfo['subnetbitsv6'] = $parts[3];
3201
				}
3202
			}
3203
		}
3204
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
3205
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
3206
	}
3207

    
3208
	return $interface_ipv6_arr_cache[$interface];
3209
}
3210

    
3211
function find_interface_subnet($interface, $flush = false)
3212
{
3213
	global $interface_sn_arr_cache;
3214
	global $interface_ip_arr_cache;
3215

    
3216
	$interface = str_replace("\n", "", $interface);
3217
	if (does_interface_exist($interface) == false)
3218
		return;
3219

    
3220
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
3221
		$ifinfo = pfSense_get_interface_addresses($interface);
3222
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
3223
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
3224
        }
3225

    
3226
	return $interface_sn_arr_cache[$interface];
3227
}
3228

    
3229
function find_interface_subnetv6($interface, $flush = false)
3230
{
3231
	global $interface_snv6_arr_cache;
3232
	global $interface_ipv6_arr_cache;
3233

    
3234
	$interface = str_replace("\n", "", $interface);
3235
	if (does_interface_exist($interface) == false)
3236
		return;
3237

    
3238
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
3239
		$ifinfo = pfSense_get_interface_addresses($interface);
3240
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
3241
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
3242
        }
3243

    
3244
	return $interface_snv6_arr_cache[$interface];
3245
}
3246

    
3247
function ip_in_interface_alias_subnet($interface, $ipalias) {
3248
	global $config;
3249

    
3250
	if (empty($interface) || !is_ipaddr($ipalias))
3251
		return false;
3252
	if (is_array($config['virtualip']['vip'])) {
3253
                foreach ($config['virtualip']['vip'] as $vip) {
3254
                        switch ($vip['mode']) {
3255
                        case "ipalias":
3256
                                if ($vip['interface'] <> $interface)
3257
                                        break;
3258
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
3259
					return true;
3260
                                break;
3261
                        }
3262
                }
3263
	}
3264

    
3265
	return false;
3266
}
3267

    
3268
function get_interface_ip($interface = "wan")
3269
{
3270
	$realif = get_real_interface($interface);
3271
	if (!$realif) {
3272
		if (preg_match("/^carp/i", $interface))
3273
			$realif = $interface;
3274
		else if (preg_match("/^vip/i", $interface))
3275
			$realif = $interface;
3276
		else
3277
			return null;
3278
	}
3279

    
3280
	$curip = find_interface_ip($realif);
3281
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
3282
		return $curip;
3283
	else
3284
		return null;
3285
}
3286

    
3287
function get_interface_ipv6($interface = "wan")
3288
{
3289
	$realif = get_real_interface($interface);
3290
	if (!$realif) {
3291
		if (preg_match("/^carp/i", $interface))
3292
			$realif = $interface;
3293
		else if (preg_match("/^vip/i", $interface))
3294
			$realif = $interface;
3295
		else
3296
			return null;
3297
	}
3298

    
3299
	$curip = find_interface_ipv6($realif);
3300
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
3301
		return $curip;
3302
	else
3303
		return null;
3304
}
3305

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

    
3318
	$cursn = find_interface_subnet($realif);
3319
	if (!empty($cursn))
3320
		return $cursn;
3321

    
3322
	return null;
3323
}
3324

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

    
3337
	$cursn = find_interface_subnetv6($realif);
3338
	if (!empty($cursn))
3339
		return $cursn;
3340

    
3341
	return null;
3342
}
3343

    
3344
/* return outside interfaces with a gateway */
3345
function get_interfaces_with_gateway() {
3346
	global $config;
3347

    
3348
	$ints = array();
3349

    
3350
	/* loop interfaces, check config for outbound */
3351
	foreach($config['interfaces'] as $ifdescr => $ifname) {
3352
		if (substr($ifdescr, 0, 5) ==  "ovpnc")
3353
			return true;
3354

    
3355
		switch ($ifname['ipaddr']) {
3356
			case "dhcp":
3357
			case "carpdev-dhcp":
3358
			case "ppp";
3359
			case "pppoe":
3360
			case "pptp":
3361
			case "l2tp":
3362
			case "ppp";
3363
				$ints[$ifdescr] = $ifdescr;
3364
			break;
3365
			default:
3366
				if (!empty($ifname['gateway']))
3367
					$ints[$ifdescr] = $ifdescr;
3368
			break;
3369
		}
3370
	}
3371
	return $ints;
3372
}
3373

    
3374
/* return true if interface has a gateway */
3375
function interface_has_gateway($friendly) {
3376
	global $config;
3377

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

    
3398
	return false;
3399
}
3400

    
3401
/****f* interfaces/is_altq_capable
3402
 * NAME
3403
 *   is_altq_capable - Test if interface is capable of using ALTQ
3404
 * INPUTS
3405
 *   $int            - string containing interface name
3406
 * RESULT
3407
 *   boolean         - true or false
3408
 ******/
3409

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

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

    
3425
        if (in_array($int_family[0], $capable))
3426
                return true;
3427
	else if (stristr($int_family, "vlan")) /* VLANs are name $parent_$vlan now */
3428
		return true;
3429
	else if (stristr($int_family, "_wlan")) /* WLANs are name $parent_$wlan now */
3430
		return true;
3431
        else
3432
                return false;
3433
}
3434

    
3435
/****f* interfaces/is_interface_wireless
3436
 * NAME
3437
 *   is_interface_wireless - Returns if an interface is wireless
3438
 * RESULT
3439
 *   $tmp       - Returns if an interface is wireless
3440
 ******/
3441
function is_interface_wireless($interface) {
3442
        global $config, $g;
3443

    
3444
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
3445
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
3446
                if (preg_match($g['wireless_regex'], $interface)) {
3447
                        if (isset($config['interfaces'][$friendly]))
3448
                                $config['interfaces'][$friendly]['wireless'] = array();
3449
                        return true;
3450
                }
3451
                return false;
3452
        } else
3453
                return true;
3454
}
3455

    
3456
function get_wireless_modes($interface) {
3457
	/* return wireless modes and channels */
3458
	$wireless_modes = array();
3459

    
3460
	$wlif = interface_translate_type_to_real($interface);
3461

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

    
3468
		$interface_channels = "";
3469
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
3470
		$interface_channel_count = count($interface_channels);
3471

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

    
3502
/* return channel numbers, frequency, max txpower, and max regulation txpower */
3503
function get_wireless_channel_info($interface) {
3504
	$wireless_channels = array();
3505

    
3506
	$wlif = interface_translate_type_to_real($interface);
3507

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

    
3514
		$interface_channels = "";
3515
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
3516

    
3517
		foreach ($interface_channels as $channel_line) {
3518
			$channel_line = explode(",", $channel_line);
3519
			if(!isset($wireless_channels[$channel_line[0]]))
3520
				$wireless_channels[$channel_line[0]] = $channel_line;
3521
		}
3522
	}
3523
	return($wireless_channels);
3524
}
3525

    
3526
/****f* interfaces/get_interface_mtu
3527
 * NAME
3528
 *   get_interface_mtu - Return the mtu of an interface
3529
 * RESULT
3530
 *   $tmp       - Returns the mtu of an interface
3531
 ******/
3532
function get_interface_mtu($interface) {
3533
        $mtu = pfSense_get_interface_addresses($interface);
3534
        return $mtu['mtu'];
3535
}
3536

    
3537
function get_interface_mac($interface) {
3538

    
3539
	$macinfo = pfSense_get_interface_addresses($interface);
3540
	return $macinfo["macaddr"];
3541
}
3542

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

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

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

    
3571
        if (in_array($int_family[0], $g['vlan_long_frame']))
3572
                return true;
3573
        else
3574
                return false;
3575
}
3576

    
3577
function setup_pppoe_reset_file($pppif, $iface="") {
3578
	global $g;
3579
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
3580

    
3581
	if(!empty($iface) && !empty($pppif)){
3582
		$cron_cmd = "#!/bin/sh\necho '<?php require(\"config.inc\"); require(\"interfaces.inc\"); interface_reconfigure({$iface}); log_error(\"PPPoE periodic reset executed on {$iface}\"); ?>' | /usr/local/bin/php -q";
3583
		file_put_contents($cron_file, $cron_cmd);
3584
		chmod($cron_file, 0700);
3585
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
3586
	} else
3587
		unlink_if_exists($cron_file);
3588
}
3589

    
3590
?>
(22-22/54)