162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci Copyright(c) 2005 Intel Corporation. All rights reserved. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci Contact Information: 862306a36Sopenharmony_ci Intel Linux Wireless <ilw@linux.intel.com> 962306a36Sopenharmony_ci Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci******************************************************************************/ 1262306a36Sopenharmony_ci#include <linux/compiler.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/if_arp.h> 1562306a36Sopenharmony_ci#include <linux/in6.h> 1662306a36Sopenharmony_ci#include <linux/in.h> 1762306a36Sopenharmony_ci#include <linux/ip.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/netdevice.h> 2162306a36Sopenharmony_ci#include <linux/proc_fs.h> 2262306a36Sopenharmony_ci#include <linux/skbuff.h> 2362306a36Sopenharmony_ci#include <linux/tcp.h> 2462306a36Sopenharmony_ci#include <linux/types.h> 2562306a36Sopenharmony_ci#include <linux/wireless.h> 2662306a36Sopenharmony_ci#include <linux/etherdevice.h> 2762306a36Sopenharmony_ci#include <linux/uaccess.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "libipw.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint libipw_is_valid_channel(struct libipw_device *ieee, u8 channel) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci int i; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* Driver needs to initialize the geography map before using 3662306a36Sopenharmony_ci * these helper functions */ 3762306a36Sopenharmony_ci if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (ieee->freq_band & LIBIPW_24GHZ_BAND) 4162306a36Sopenharmony_ci for (i = 0; i < ieee->geo.bg_channels; i++) 4262306a36Sopenharmony_ci /* NOTE: If G mode is currently supported but 4362306a36Sopenharmony_ci * this is a B only channel, we don't see it 4462306a36Sopenharmony_ci * as valid. */ 4562306a36Sopenharmony_ci if ((ieee->geo.bg[i].channel == channel) && 4662306a36Sopenharmony_ci !(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) && 4762306a36Sopenharmony_ci (!(ieee->mode & IEEE_G) || 4862306a36Sopenharmony_ci !(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY))) 4962306a36Sopenharmony_ci return LIBIPW_24GHZ_BAND; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (ieee->freq_band & LIBIPW_52GHZ_BAND) 5262306a36Sopenharmony_ci for (i = 0; i < ieee->geo.a_channels; i++) 5362306a36Sopenharmony_ci if ((ieee->geo.a[i].channel == channel) && 5462306a36Sopenharmony_ci !(ieee->geo.a[i].flags & LIBIPW_CH_INVALID)) 5562306a36Sopenharmony_ci return LIBIPW_52GHZ_BAND; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ciint libipw_channel_to_index(struct libipw_device *ieee, u8 channel) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci int i; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* Driver needs to initialize the geography map before using 6562306a36Sopenharmony_ci * these helper functions */ 6662306a36Sopenharmony_ci if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) 6762306a36Sopenharmony_ci return -1; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (ieee->freq_band & LIBIPW_24GHZ_BAND) 7062306a36Sopenharmony_ci for (i = 0; i < ieee->geo.bg_channels; i++) 7162306a36Sopenharmony_ci if (ieee->geo.bg[i].channel == channel) 7262306a36Sopenharmony_ci return i; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (ieee->freq_band & LIBIPW_52GHZ_BAND) 7562306a36Sopenharmony_ci for (i = 0; i < ieee->geo.a_channels; i++) 7662306a36Sopenharmony_ci if (ieee->geo.a[i].channel == channel) 7762306a36Sopenharmony_ci return i; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return -1; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciu32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci const struct libipw_channel * ch; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Driver needs to initialize the geography map before using 8762306a36Sopenharmony_ci * these helper functions */ 8862306a36Sopenharmony_ci if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci ch = libipw_get_channel(ieee, channel); 9262306a36Sopenharmony_ci if (!ch->channel) 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci return ch->freq; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciu8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci int i; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Driver needs to initialize the geography map before using 10262306a36Sopenharmony_ci * these helper functions */ 10362306a36Sopenharmony_ci if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci freq /= 100000; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (ieee->freq_band & LIBIPW_24GHZ_BAND) 10962306a36Sopenharmony_ci for (i = 0; i < ieee->geo.bg_channels; i++) 11062306a36Sopenharmony_ci if (ieee->geo.bg[i].freq == freq) 11162306a36Sopenharmony_ci return ieee->geo.bg[i].channel; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (ieee->freq_band & LIBIPW_52GHZ_BAND) 11462306a36Sopenharmony_ci for (i = 0; i < ieee->geo.a_channels; i++) 11562306a36Sopenharmony_ci if (ieee->geo.a[i].freq == freq) 11662306a36Sopenharmony_ci return ieee->geo.a[i].channel; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_civoid libipw_set_geo(struct libipw_device *ieee, 12262306a36Sopenharmony_ci const struct libipw_geo *geo) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci memcpy(ieee->geo.name, geo->name, 3); 12562306a36Sopenharmony_ci ieee->geo.name[3] = '\0'; 12662306a36Sopenharmony_ci ieee->geo.bg_channels = geo->bg_channels; 12762306a36Sopenharmony_ci ieee->geo.a_channels = geo->a_channels; 12862306a36Sopenharmony_ci memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * 12962306a36Sopenharmony_ci sizeof(struct libipw_channel)); 13062306a36Sopenharmony_ci memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * 13162306a36Sopenharmony_ci sizeof(struct libipw_channel)); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciconst struct libipw_geo *libipw_get_geo(struct libipw_device *ieee) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci return &ieee->geo; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciu8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci int index = libipw_channel_to_index(ieee, channel); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (index == -1) 14462306a36Sopenharmony_ci return LIBIPW_CH_INVALID; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (channel <= LIBIPW_24GHZ_CHANNELS) 14762306a36Sopenharmony_ci return ieee->geo.bg[index].flags; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return ieee->geo.a[index].flags; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic const struct libipw_channel bad_channel = { 15362306a36Sopenharmony_ci .channel = 0, 15462306a36Sopenharmony_ci .flags = LIBIPW_CH_INVALID, 15562306a36Sopenharmony_ci .max_power = 0, 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ciconst struct libipw_channel *libipw_get_channel(struct libipw_device 15962306a36Sopenharmony_ci *ieee, u8 channel) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci int index = libipw_channel_to_index(ieee, channel); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (index == -1) 16462306a36Sopenharmony_ci return &bad_channel; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (channel <= LIBIPW_24GHZ_CHANNELS) 16762306a36Sopenharmony_ci return &ieee->geo.bg[index]; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return &ieee->geo.a[index]; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_get_channel); 17362306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_get_channel_flags); 17462306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_is_valid_channel); 17562306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_freq_to_channel); 17662306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_channel_to_freq); 17762306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_channel_to_index); 17862306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_set_geo); 17962306a36Sopenharmony_ciEXPORT_SYMBOL(libipw_get_geo); 180