ieee80211_ioctl.c (187800) | ieee80211_ioctl.c (187801) |
---|---|
1/*- 2 * Copyright (c) 2001 Atsushi Onoe 3 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 11 unchanged lines hidden (view full) --- 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2001 Atsushi Onoe 3 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 11 unchanged lines hidden (view full) --- 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> |
28__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ioctl.c 187800 2009-01-27 23:19:36Z sam $"); | 28__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ioctl.c 187801 2009-01-27 23:42:14Z sam $"); |
29 30/* 31 * IEEE 802.11 ioctl support (FreeBSD-specific) 32 */ 33 34#include "opt_inet.h" 35#include "opt_ipx.h" 36#include "opt_wlan.h" --- 654 unchanged lines hidden (view full) --- 691} 692 693static __noinline int 694ieee80211_ioctl_getdevcaps(struct ieee80211com *ic, 695 const struct ieee80211req *ireq) 696{ 697 struct ieee80211_devcaps_req *dc; 698 struct ieee80211req_chaninfo *ci; | 29 30/* 31 * IEEE 802.11 ioctl support (FreeBSD-specific) 32 */ 33 34#include "opt_inet.h" 35#include "opt_ipx.h" 36#include "opt_wlan.h" --- 654 unchanged lines hidden (view full) --- 691} 692 693static __noinline int 694ieee80211_ioctl_getdevcaps(struct ieee80211com *ic, 695 const struct ieee80211req *ireq) 696{ 697 struct ieee80211_devcaps_req *dc; 698 struct ieee80211req_chaninfo *ci; |
699 int error; | 699 int maxchans, error; |
700 | 700 |
701 if (ireq->i_len != sizeof(struct ieee80211_devcaps_req)) | 701 maxchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_devcaps_req)) / 702 sizeof(struct ieee80211_channel)); 703 /* NB: require 1 so we know ic_nchans is accessible */ 704 if (maxchans < 1) |
702 return EINVAL; | 705 return EINVAL; |
703 dc = (struct ieee80211_devcaps_req *) malloc( 704 sizeof(struct ieee80211_devcaps_req), M_TEMP, M_NOWAIT | M_ZERO); | 706 /* constrain max request size, 2K channels is ~24Kbytes */ 707 if (maxchans > 2048) 708 maxchans = 2048; 709 dc = (struct ieee80211_devcaps_req *) 710 malloc(IEEE80211_DEVCAPS_SIZE(maxchans), M_TEMP, M_NOWAIT | M_ZERO); |
705 if (dc == NULL) 706 return ENOMEM; 707 dc->dc_drivercaps = ic->ic_caps; 708 dc->dc_cryptocaps = ic->ic_cryptocaps; 709 dc->dc_htcaps = ic->ic_htcaps; 710 ci = &dc->dc_chaninfo; | 711 if (dc == NULL) 712 return ENOMEM; 713 dc->dc_drivercaps = ic->ic_caps; 714 dc->dc_cryptocaps = ic->ic_cryptocaps; 715 dc->dc_htcaps = ic->ic_htcaps; 716 ci = &dc->dc_chaninfo; |
711 ic->ic_getradiocaps(ic, IEEE80211_CHAN_MAX, &ci->ic_nchans, ci->ic_chans); | 717 ic->ic_getradiocaps(ic, maxchans, &ci->ic_nchans, ci->ic_chans); |
712 ieee80211_sort_channels(ci->ic_chans, ci->ic_nchans); | 718 ieee80211_sort_channels(ci->ic_chans, ci->ic_nchans); |
713 error = copyout(dc, ireq->i_data, sizeof(*dc)); | 719 error = copyout(dc, ireq->i_data, IEEE80211_DEVCAPS_SPACE(dc)); |
714 free(dc, M_TEMP); 715 return error; 716} 717 718static __noinline int 719ieee80211_ioctl_getstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq) 720{ 721 struct ieee80211_node *ni; --- 839 unchanged lines hidden (view full) --- 1561 } 1562 return 0; 1563} 1564 1565static __noinline int 1566ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) 1567{ 1568 struct ieee80211com *ic = vap->iv_ic; | 720 free(dc, M_TEMP); 721 return error; 722} 723 724static __noinline int 725ieee80211_ioctl_getstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq) 726{ 727 struct ieee80211_node *ni; --- 839 unchanged lines hidden (view full) --- 1567 } 1568 return 0; 1569} 1570 1571static __noinline int 1572ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) 1573{ 1574 struct ieee80211com *ic = vap->iv_ic; |
1569 struct ieee80211req_chanlist list; 1570 u_char chanlist[IEEE80211_CHAN_BYTES]; 1571 int i, nchan, error; | 1575 uint8_t *chanlist, *list; 1576 int i, nchan, maxchan, error; |
1572 | 1577 |
1573 if (ireq->i_len != sizeof(list)) 1574 return EINVAL; 1575 error = copyin(ireq->i_data, &list, sizeof(list)); | 1578 if (ireq->i_len > sizeof(ic->ic_chan_active)) 1579 ireq->i_len = sizeof(ic->ic_chan_active); 1580 list = malloc(ireq->i_len + IEEE80211_CHAN_BYTES, M_TEMP, 1581 M_NOWAIT | M_ZERO); 1582 if (list == NULL) 1583 return ENOMEM; 1584 error = copyin(ireq->i_data, list, ireq->i_len); |
1576 if (error) 1577 return error; | 1585 if (error) 1586 return error; |
1578 memset(chanlist, 0, sizeof(chanlist)); | |
1579 nchan = 0; | 1587 nchan = 0; |
1588 chanlist = list + ireq->i_len; /* NB: zero'd already */ 1589 maxchan = ireq->i_len * NBBY; |
|
1580 for (i = 0; i < ic->ic_nchans; i++) { 1581 const struct ieee80211_channel *c = &ic->ic_channels[i]; 1582 /* 1583 * Calculate the intersection of the user list and the 1584 * available channels so users can do things like specify 1585 * 1-255 to get all available channels. 1586 */ | 1590 for (i = 0; i < ic->ic_nchans; i++) { 1591 const struct ieee80211_channel *c = &ic->ic_channels[i]; 1592 /* 1593 * Calculate the intersection of the user list and the 1594 * available channels so users can do things like specify 1595 * 1-255 to get all available channels. 1596 */ |
1587 if (isset(list.ic_channels, c->ic_ieee)) { | 1597 if (c->ic_ieee < maxchan && isset(list, c->ic_ieee)) { |
1588 setbit(chanlist, c->ic_ieee); 1589 nchan++; 1590 } 1591 } 1592 if (nchan == 0) 1593 return EINVAL; 1594 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */ 1595 isclr(chanlist, ic->ic_bsschan->ic_ieee)) 1596 ic->ic_bsschan = IEEE80211_CHAN_ANYC; | 1598 setbit(chanlist, c->ic_ieee); 1599 nchan++; 1600 } 1601 } 1602 if (nchan == 0) 1603 return EINVAL; 1604 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */ 1605 isclr(chanlist, ic->ic_bsschan->ic_ieee)) 1606 ic->ic_bsschan = IEEE80211_CHAN_ANYC; |
1597 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active)); | 1607 memcpy(ic->ic_chan_active, chanlist, IEEE80211_CHAN_BYTES); |
1598 ieee80211_scan_flush(vap); | 1608 ieee80211_scan_flush(vap); |
1609 free(list, M_TEMP); |
|
1599 return ENETRESET; 1600} 1601 1602static __noinline int 1603ieee80211_ioctl_setstastats(struct ieee80211vap *vap, struct ieee80211req *ireq) 1604{ 1605 struct ieee80211_node *ni; 1606 uint8_t macaddr[IEEE80211_ADDR_LEN]; --- 381 unchanged lines hidden (view full) --- 1988 return setcurchan(vap, c); 1989} 1990 1991static __noinline int 1992ieee80211_ioctl_setregdomain(struct ieee80211vap *vap, 1993 const struct ieee80211req *ireq) 1994{ 1995 struct ieee80211_regdomain_req *reg; | 1610 return ENETRESET; 1611} 1612 1613static __noinline int 1614ieee80211_ioctl_setstastats(struct ieee80211vap *vap, struct ieee80211req *ireq) 1615{ 1616 struct ieee80211_node *ni; 1617 uint8_t macaddr[IEEE80211_ADDR_LEN]; --- 381 unchanged lines hidden (view full) --- 1999 return setcurchan(vap, c); 2000} 2001 2002static __noinline int 2003ieee80211_ioctl_setregdomain(struct ieee80211vap *vap, 2004 const struct ieee80211req *ireq) 2005{ 2006 struct ieee80211_regdomain_req *reg; |
1996 int error; | 2007 int nchans, error; |
1997 | 2008 |
1998 if (ireq->i_len != sizeof(struct ieee80211_regdomain_req)) | 2009 nchans = 1 + ((ireq->i_len - sizeof(struct ieee80211_regdomain_req)) / 2010 sizeof(struct ieee80211_channel)); 2011 if (!(1 <= nchans && nchans <= IEEE80211_CHAN_MAX)) { 2012 IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL, 2013 "%s: bad # chans, i_len %d nchans %d\n", __func__, 2014 ireq->i_len, nchans); |
1999 return EINVAL; | 2015 return EINVAL; |
2000 reg = (struct ieee80211_regdomain_req *) malloc( 2001 sizeof(struct ieee80211_regdomain_req), M_TEMP, M_NOWAIT); 2002 if (reg == NULL) | 2016 } 2017 reg = (struct ieee80211_regdomain_req *) 2018 malloc(IEEE80211_REGDOMAIN_SIZE(nchans), M_TEMP, M_NOWAIT); 2019 if (reg == NULL) { 2020 IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL, 2021 "%s: no memory, nchans %d\n", __func__, nchans); |
2003 return ENOMEM; | 2022 return ENOMEM; |
2004 error = copyin(ireq->i_data, reg, sizeof(*reg)); 2005 if (error == 0) 2006 error = ieee80211_setregdomain(vap, reg); | 2023 } 2024 error = copyin(ireq->i_data, reg, IEEE80211_REGDOMAIN_SIZE(nchans)); 2025 if (error == 0) { 2026 /* NB: validate inline channel count against storage size */ 2027 if (reg->chaninfo.ic_nchans != nchans) { 2028 IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL, 2029 "%s: chan cnt mismatch, %d != %d\n", __func__, 2030 reg->chaninfo.ic_nchans, nchans); 2031 error = EINVAL; 2032 } else 2033 error = ieee80211_setregdomain(vap, reg); 2034 } |
2007 free(reg, M_TEMP); 2008 2009 return (error == 0 ? ENETRESET : error); 2010} 2011 2012static int 2013ieee80211_ioctl_setroam(struct ieee80211vap *vap, 2014 const struct ieee80211req *ireq) --- 1315 unchanged lines hidden --- | 2035 free(reg, M_TEMP); 2036 2037 return (error == 0 ? ENETRESET : error); 2038} 2039 2040static int 2041ieee80211_ioctl_setroam(struct ieee80211vap *vap, 2042 const struct ieee80211req *ireq) --- 1315 unchanged lines hidden --- |