[RFC] S1G: Add support for freq_khz

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Gilad Itzkovitch <gilad.itzkovitch@xxxxxxxxxxxxxx>

This commit adds support for specifying a frequency in khz. The
predominate use case is S1G. Many S1G channels are centered on frequencies
which a MHz value does not support. Additional freq_khz parameters have
been added as required to the key structures that maintain the operating
parameters of a hostapd AP. These freq_khz params have been added to key
functions alongside the traditional freq parameter as an alternative.

The extent of this commit is the support of core BSS functionality using
freq_khz. It is intended that several follow up commits will make use of
this concept to support more advanced features.

Because this commit has introduced an alternative parameter that is used
instead of the traditional freq param we needed to introduce logic that
would support this change. We opted for logic that checks if freq_khz is
set, and if so, uses that parameter going forward, otherwise if freq_khz
is not set, freq is used as per the existing use case.
This approach prevents regression for existing code.

The kernel maintains frequencies by using a combination of freq and
freq_offset parameters. This patch includes a number of changes to support
this concept.

Signed-off-by: Gilad Itzkovitch <gilad.itzkovitch@xxxxxxxxxxxxxx>
---
 src/ap/ap_drv_ops.c                |  8 +++--
 src/ap/ap_drv_ops.h                |  3 +-
 src/ap/beacon.c                    |  1 +
 src/ap/dfs.c                       |  9 ++++--
 src/ap/drv_callbacks.c             | 10 +++---
 src/ap/hostapd.c                   |  6 ++--
 src/ap/hostapd.h                   | 10 ++++--
 src/ap/hw_features.c               | 50 ++++++++++++++++++------------
 src/ap/hw_features.h               |  2 +-
 src/common/defs.h                  |  6 ++++
 src/common/hw_features_common.c    | 28 +++++++++++------
 src/common/hw_features_common.h    | 13 +++++---
 src/common/ieee802_11_common.c     | 13 ++++++++
 src/common/ieee802_11_common.h     |  2 ++
 src/drivers/driver.h               | 14 +++++++++
 src/drivers/driver_nl80211.c       | 25 +++++++++++++--
 src/drivers/driver_nl80211_capa.c  |  7 ++++-
 src/drivers/driver_nl80211_event.c | 19 +++++++++---
 wpa_supplicant/ap.c                | 12 ++++---
 wpa_supplicant/ap.h                |  4 +--
 wpa_supplicant/config_ssid.h       |  5 +++
 wpa_supplicant/events.c            |  1 +
 wpa_supplicant/mesh.c              |  1 +
 wpa_supplicant/wpa_supplicant.c    |  4 ++-
 wpa_supplicant/wpa_supplicant_i.h  |  1 +
 25 files changed, 189 insertions(+), 65 deletions(-)

diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 1ffc37ff3..ae059905c 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -557,7 +557,8 @@ int hostapd_flush(struct hostapd_data *hapd)
 
 
 int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
-		     int freq, int channel, int edmg, u8 edmg_channel,
+		     int freq, int freq_khz, int channel,
+		     int edmg, u8 edmg_channel,
 		     int ht_enabled, int vht_enabled,
 		     int he_enabled, bool eht_enabled,
 		     int sec_channel_offset, int oper_chwidth,
@@ -566,7 +567,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
 	struct hostapd_freq_params data;
 	struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
 
-	if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
+	if (hostapd_set_freq_params(&data, mode, freq, freq_khz,
+				    channel, edmg,
 				    edmg_channel, ht_enabled,
 				    vht_enabled, he_enabled, eht_enabled,
 				    sec_channel_offset, oper_chwidth,
@@ -845,7 +847,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
 		return -1;
 	}
 
-	if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
+	if (hostapd_set_freq_params(&data, mode, freq, 0, channel, 0, 0,
 				    ht_enabled,
 				    vht_enabled, he_enabled, eht_enabled,
 				    sec_channel_offset,
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 93b224499..2286a7a20 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -65,7 +65,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
 		       const u8 *addr, int idx, u8 *seq);
 int hostapd_flush(struct hostapd_data *hapd);
 int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
-		     int freq, int channel, int edmg, u8 edmg_channel,
+		     int freq, int freq_khz,
+		     int channel, int edmg, u8 edmg_channel,
 		     int ht_enabled, int vht_enabled, int he_enabled,
 		     bool eht_enabled, int sec_channel_offset, int oper_chwidth,
 		     int center_segment0, int center_segment1);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index d73734351..0f84c1e42 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2073,6 +2073,7 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
 
 	if (cmode &&
 	    hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+				    iface->freq_khz,
 				    iconf->channel, iconf->enable_edmg,
 				    iconf->edmg_channel, iconf->ieee80211n,
 				    iconf->ieee80211ac, iconf->ieee80211ax,
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index e8c5ec9ac..2e275de7e 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -826,6 +826,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
 	if (is_6ghz_freq(iface->freq))
 		return 1;
 
+	if (is_s1g_freq(iface->freq_khz))
+		return 1;
+
 	if (!iface->current_mode) {
 		/*
 		 * This can happen with drivers that do not provide mode
@@ -955,6 +958,7 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
 
 static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
 					      int channel, int freq,
+					      int freq_khz,
 					      int secondary_channel,
 					      u8 current_vht_oper_chwidth,
 					      u8 oper_centr_freq_seg0_idx,
@@ -984,7 +988,7 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
 #endif /* CONFIG_MESH */
 	err = hostapd_set_freq_params(&csa_settings.freq_params,
 				      iface->conf->hw_mode,
-				      freq, channel,
+				      freq, freq_khz, channel,
 				      iface->conf->enable_edmg,
 				      iface->conf->edmg_channel,
 				      iface->conf->ieee80211n,
@@ -1117,7 +1121,7 @@ hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
 	hostpad_dfs_update_background_chain(iface);
 
 	return hostapd_dfs_request_channel_switch(
-		iface, iface->conf->channel, iface->freq,
+		iface, iface->conf->channel, iface->freq, 0,
 		iface->conf->secondary_channel, current_vht_oper_chwidth,
 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
@@ -1409,6 +1413,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
 
 	return hostapd_dfs_request_channel_switch(iface, channel->chan,
 						  channel->freq,
+						  channel->freq_khz,
 						  secondary_channel,
 						  current_vht_oper_chwidth,
 						  oper_centr_freq_seg0_idx,
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 71c905ba6..33b4ef05b 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -857,8 +857,8 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
-void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset, int width, int cf1, int cf2,
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int freq_khz,
+			     int ht, int offset, int width, int cf1, int cf2,
 			     int finished)
 {
 #ifdef NEED_AP_MLME
@@ -888,7 +888,7 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 	is_dfs0 = hostapd_is_dfs_required(hapd->iface);
 	hapd->iface->freq = freq;
 
-	channel = hostapd_hw_get_channel(hapd, freq);
+	channel = hostapd_hw_get_channel(hapd, freq, freq_khz);
 	if (!channel) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_WARNING,
@@ -1107,6 +1107,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
 				if (hapd->iface->freq > 0 &&
 				    !hw_get_chan(mode->mode,
 						 hapd->iface->freq,
+						 hapd->iface->freq_khz,
 						 hapd->iface->hw_features,
 						 hapd->iface->num_hw_features))
 					continue;
@@ -1131,7 +1132,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
 		goto out;
 	}
 	pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
-				       acs_res->pri_freq, NULL,
+				       acs_res->pri_freq, 0, NULL,
 				       hapd->iface->hw_features,
 				       hapd->iface->num_hw_features);
 	if (!pri_chan) {
@@ -2020,6 +2021,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		if (!data)
 			break;
 		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
+					data->ch_switch.freq_khz,
 					data->ch_switch.ht_enabled,
 					data->ch_switch.ch_offset,
 					data->ch_switch.ch_width,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 58492e51e..b76564543 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2136,7 +2136,8 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
 #endif /* CONFIG_MESH */
 
 		if (!delay_apply_cfg &&
-		    hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+		    hostapd_set_freq(hapd, hapd->iconf->hw_mode,
+				     iface->freq, iface->freq_khz,
 				     hapd->iconf->channel,
 				     hapd->iconf->enable_edmg,
 				     hapd->iconf->edmg_channel,
@@ -3546,7 +3547,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 
 	if (!params->channel) {
 		/* check if the new channel is supported by hw */
-		params->channel = hostapd_hw_get_channel(hapd, params->freq);
+		params->channel = hostapd_hw_get_channel(hapd, params->freq, 0);
 	}
 
 	channel = params->channel;
@@ -3559,6 +3560,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 	if (old_params &&
 	    hostapd_set_freq_params(old_params, conf->hw_mode,
 				    hostapd_hw_get_freq(hapd, conf->channel),
+				    0,
 				    conf->channel, conf->enable_edmg,
 				    conf->edmg_channel, conf->ieee80211n,
 				    conf->ieee80211ac, conf->ieee80211ax,
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index ed2ff4587..61ac5ac96 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -551,6 +551,12 @@ struct hostapd_iface {
 	struct hostapd_rate_data *current_rates;
 	int *basic_rates;
 	int freq;
+	/*
+	 * freq_khz was added to support S1G frequencies.
+	 * This variable could be use in other modes of operation.
+	 * However, this is not currently supported.
+	 */
+	int freq_khz;
 
 	/* Background radar configuration */
 	struct {
@@ -724,8 +730,8 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
 int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
 			 const u8 *bssid, const u8 *ie, size_t ie_len,
 			 int ssi_signal);
-void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset, int width, int cf1, int cf2,
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int freq_khz,
+			     int ht, int offset, int width, int cf1, int cf2,
 			     int finished);
 struct survey_results;
 void hostapd_event_get_survey(struct hostapd_iface *iface,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index ed5ff41d3..94520860b 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -235,11 +235,11 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
 	if (!iface->current_mode)
 		return 0;
 
-	p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
+	p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, 0, NULL,
 				     iface->hw_features,
 				     iface->num_hw_features);
 
-	s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
+	s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, 0, NULL,
 				     iface->hw_features,
 				     iface->num_hw_features);
 
@@ -274,10 +274,10 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
 
 	if (!iface->current_mode)
 		return 0;
-	pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
+	pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, 0,
 				       NULL, iface->hw_features,
 				       iface->num_hw_features);
-	sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
+	sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, 0,
 				       NULL, iface->hw_features,
 				       iface->num_hw_features);
 
@@ -795,15 +795,16 @@ int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
 
 
 static int hostapd_is_usable_chan(struct hostapd_iface *iface,
-				  int frequency, int primary)
+				  int frequency, int frequency_khz, int primary)
 {
 	struct hostapd_channel_data *chan;
 
 	if (!iface->current_mode)
 		return 0;
 
-	chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
-				   iface->hw_features, iface->num_hw_features);
+	chan = hw_get_channel_freq(iface->current_mode->mode, frequency,
+				   frequency_khz, NULL, iface->hw_features,
+				   iface->num_hw_features);
 	if (!chan)
 		return 0;
 
@@ -813,7 +814,8 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
 
 	wpa_printf(MSG_INFO,
 		   "Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
-		   frequency, primary ? "primary" : "secondary",
+		   frequency_khz ? frequency_khz : frequency,
+		   primary ? "primary" : "secondary",
 		   chan->flag,
 		   chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
 		   chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
@@ -835,7 +837,8 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
 	if (!iface->current_mode)
 		return 0;
 	pri_chan = hw_get_channel_freq(iface->current_mode->mode,
-				       iface->freq, NULL,
+				       iface->freq,
+				       iface->freq_khz, NULL,
 				       iface->hw_features,
 				       iface->num_hw_features);
 	if (!pri_chan)
@@ -865,7 +868,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
 		if (num_of_enabled > 4)
 			return 0;
 
-		if (!hostapd_is_usable_chan(iface, freq, 1))
+		if (!hostapd_is_usable_chan(iface, freq, 0, 1))
 			return 0;
 
 		if (contiguous > max_contiguous)
@@ -900,18 +903,23 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 
 	if (!iface->current_mode)
 		return 0;
+
 	pri_chan = hw_get_channel_freq(iface->current_mode->mode,
-				       iface->freq, NULL,
+				       iface->freq,
+				       iface->freq_khz, NULL,
 				       iface->hw_features,
 				       iface->num_hw_features);
 	if (!pri_chan) {
 		wpa_printf(MSG_ERROR, "Primary frequency not present");
 		return 0;
 	}
-	if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
+	if (!hostapd_is_usable_chan(iface, pri_chan->freq,
+				    pri_chan->freq_khz,
+				    pri_chan->freq_khz ? 0 : 1)) {
 		wpa_printf(MSG_ERROR, "Primary frequency not allowed");
 		return 0;
 	}
+
 	if (!hostapd_is_usable_edmg(iface))
 		return 0;
 
@@ -919,7 +927,7 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 		return 1;
 
 	if (hostapd_is_usable_chan(iface, iface->freq +
-				   iface->conf->secondary_channel * 20, 0)) {
+				   iface->conf->secondary_channel * 20, 0, 0)) {
 		if (iface->conf->secondary_channel == 1 &&
 		    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
 			return 1;
@@ -932,14 +940,14 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 
 	/* Both HT40+ and HT40- are set, pick a valid secondary channel */
 	secondary_freq = iface->freq + 20;
-	if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
+	if (hostapd_is_usable_chan(iface, secondary_freq, 0, 0) &&
 	    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
 		iface->conf->secondary_channel = 1;
 		return 1;
 	}
 
 	secondary_freq = iface->freq - 20;
-	if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
+	if (hostapd_is_usable_chan(iface, secondary_freq, 0, 0) &&
 	    (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
 		iface->conf->secondary_channel = -1;
 		return 1;
@@ -984,7 +992,7 @@ static void hostapd_determine_mode(struct hostapd_iface *iface)
 static enum hostapd_chan_status
 hostapd_check_chans(struct hostapd_iface *iface)
 {
-	if (iface->freq) {
+	if (iface->freq || iface->freq_khz) {
 		hostapd_determine_mode(iface);
 		if (hostapd_is_usable_chans(iface))
 			return HOSTAPD_CHAN_VALID;
@@ -1103,8 +1111,9 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
 		int chan;
 
 		if (mode->mode == iface->conf->hw_mode) {
-			if (iface->freq > 0 &&
-			    !hw_mode_get_channel(mode, iface->freq, &chan))
+			if ((iface->freq > 0 || iface->freq_khz > 0) &&
+			    !hw_mode_get_channel(mode, iface->freq,
+						 iface->freq_khz, &chan))
 				continue;
 
 			iface->current_mode = mode;
@@ -1169,13 +1178,14 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
 }
 
 
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq, int freq_khz)
 {
 	int i, channel;
 	struct hostapd_hw_modes *mode;
 
 	if (hapd->iface->current_mode) {
 		channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
+				      freq_khz,
 				      hapd->iface->hw_features,
 				      hapd->iface->num_hw_features);
 		if (channel)
@@ -1188,7 +1198,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
 		return 0;
 	for (i = 0; i < hapd->iface->num_hw_features; i++) {
 		mode = &hapd->iface->hw_features[i];
-		channel = hw_get_chan(mode->mode, freq,
+		channel = hw_get_chan(mode->mode, freq, freq_khz,
 				      hapd->iface->hw_features,
 				      hapd->iface->num_hw_features);
 		if (channel)
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index ad0ddf7ff..5029c6560 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -19,7 +19,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err);
 int hostapd_select_hw_mode(struct hostapd_iface *iface);
 const char * hostapd_hw_mode_txt(int mode);
 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq, int freq_khz);
 int hostapd_check_ht_capab(struct hostapd_iface *iface);
 int hostapd_check_edmg_capab(struct hostapd_iface *iface);
 int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface);
diff --git a/src/common/defs.h b/src/common/defs.h
index c0c6dbe84..b92146406 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -529,4 +529,10 @@ enum sae_pwe {
 	SAE_PWE_NOT_SET = 4,
 };
 
+#define MHZ_TO_KHZ(x) ((x) * 1000)
+#define KHZ_TO_MHZ(x) ((x) / 1000)
+#define KHZ_TO_S1G_OFFSET(x) ((x) % 1000)
+/* If x (freq_khz) is 0 then print "MHz" else print "kHz" */
+#define KHZ_PRINT_FREQ_UNITS(x) (x) == 0 ? "MHz" : "kHz"
+
 #endif /* DEFS_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 6646301df..0b8e9ce36 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -41,14 +41,17 @@ struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
 
 
 struct hostapd_channel_data *
-hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq,
+		    int freq_khz, int *chan)
 {
 	int i;
 
 	for (i = 0; i < mode->num_channels; i++) {
 		struct hostapd_channel_data *ch = &mode->channels[i];
-
-		if (ch->freq == freq) {
+		if (freq_khz && (ch->freq_khz == freq_khz)) {
+			return ch;
+		}
+		if (freq && (ch->freq == freq)) {
 			if (chan)
 				*chan = ch->chan;
 			return ch;
@@ -60,8 +63,9 @@ hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
 
 
 struct hostapd_channel_data *
-hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
-		    struct hostapd_hw_modes *hw_features, int num_hw_features)
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int freq_khz,
+		    int *chan, struct hostapd_hw_modes *hw_features,
+		    int num_hw_features)
 {
 	struct hostapd_channel_data *chan_data;
 	int i;
@@ -78,7 +82,8 @@ hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
 		if (curr_mode->mode != mode)
 			continue;
 
-		chan_data = hw_mode_get_channel(curr_mode, freq, chan);
+		chan_data = hw_mode_get_channel(curr_mode, freq,
+						freq_khz, chan);
 		if (chan_data)
 			return chan_data;
 	}
@@ -97,12 +102,13 @@ int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
 }
 
 
-int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+int hw_get_chan(enum hostapd_hw_mode mode, int freq, int freq_khz,
 		struct hostapd_hw_modes *hw_features, int num_hw_features)
 {
 	int chan;
 
-	hw_get_channel_freq(mode, freq, &chan, hw_features, num_hw_features);
+	hw_get_channel_freq(mode, freq, freq_khz, &chan, hw_features,
+			    num_hw_features);
 
 	return chan;
 }
@@ -380,10 +386,11 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
 
 int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int enable_edmg,
+			    int freq, int freq_khz,
+			    int channel, int enable_edmg,
 			    u8 edmg_channel, int ht_enabled,
 			    int vht_enabled, int he_enabled,
-			    bool eht_enabled, int sec_channel_offset,
+				bool eht_enabled, int sec_channel_offset,
 			    enum oper_chan_width oper_chwidth,
 			    int center_segment0,
 			    int center_segment1, u32 vht_caps,
@@ -397,6 +404,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
 	os_memset(data, 0, sizeof(*data));
 	data->mode = mode;
 	data->freq = freq;
+	data->freq_khz = freq_khz;
 	data->channel = channel;
 	data->ht_enabled = ht_enabled;
 	data->vht_enabled = vht_enabled;
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index d8ca16867..86214dc19 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -15,14 +15,16 @@
 struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
 						  int chan, int *freq);
 struct hostapd_channel_data *
-hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan);
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq,
+		    int freq_khz, int *chan);
 
 struct hostapd_channel_data *
-hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
-		    struct hostapd_hw_modes *hw_features, int num_hw_features);
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int freq_khz,
+		    int *chan, struct hostapd_hw_modes *hw_features,
+		    int num_hw_features);
 
 int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
-int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+int hw_get_chan(enum hostapd_hw_mode mode, int freq, int freq_khz,
 		struct hostapd_hw_modes *hw_features, int num_hw_features);
 
 int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
@@ -37,7 +39,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
 		    int sec_chan);
 int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    enum hostapd_hw_mode mode,
-			    int freq, int channel, int edmg, u8 edmg_channel,
+			    int freq, int freq_khz,
+			    int channel, int edmg, u8 edmg_channel,
 			    int ht_enabled,
 			    int vht_enabled, int he_enabled,
 			    bool eht_enabled, int sec_channel_offset,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 7741a8df8..86e27e0e1 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -957,6 +957,10 @@ ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
 
 	/* TODO: more operating classes */
 
+	/* S1G is not currently supported */
+	if (is_s1g_freq(MHZ_TO_KHZ(freq)))
+		return NUM_HOSTAPD_MODES;
+
 	if (sec_channel > 1 || sec_channel < -1)
 		return NUM_HOSTAPD_MODES;
 
@@ -2409,6 +2413,15 @@ int get_6ghz_sec_channel(int channel)
 }
 
 
+bool is_s1g_freq(int freq_khz)
+{
+	if (freq_khz < 1000000 && freq_khz > 0)
+		return true;
+
+	return false;
+}
+
+
 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
 				    size_t nei_rep_len)
 {
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9a1dbdda8..2ca572fcf 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -273,6 +273,8 @@ bool is_6ghz_op_class(u8 op_class);
 bool is_6ghz_psc_frequency(int freq);
 int get_6ghz_sec_channel(int channel);
 
+bool is_s1g_freq(int freq_khz);
+
 int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
 				    size_t nei_rep_len);
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 46182552d..15d844cad 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -119,6 +119,11 @@ struct hostapd_channel_data {
 	 */
 	int freq;
 
+	/**
+	 * freq_khz - Frequency in kHz
+	 */
+	int freq_khz;
+
 	/**
 	 * flag - Channel flags (HOSTAPD_CHAN_*)
 	 */
@@ -761,6 +766,11 @@ struct hostapd_freq_params {
 	 */
 	int freq;
 
+	/**
+	 * freq_khz - Primary channel center frequency in kHz
+	 */
+	int freq_khz;
+
 	/**
 	 * channel - Channel number
 	 */
@@ -6288,6 +6298,7 @@ union wpa_event_data {
 	/**
 	 * struct ch_switch
 	 * @freq: Frequency of new channel in MHz
+	 * @freq_khz: Frequency of new channel in kHz
 	 * @ht_enabled: Whether this is an HT channel
 	 * @ch_offset: Secondary channel offset
 	 * @ch_width: Channel width
@@ -6297,6 +6308,7 @@ union wpa_event_data {
 	 */
 	struct ch_switch {
 		int freq;
+		int freq_khz;
 		int ht_enabled;
 		int ch_offset;
 		enum chan_width ch_width;
@@ -6379,6 +6391,7 @@ union wpa_event_data {
 	/**
 	 * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
 	 * @pri_freq: Selected primary frequency
+	 * @pri_freq_khz: Selected primary frequency in kHz
 	 * @sec_freq: Selected secondary frequency
 	 * @edmg_channel: Selected EDMG channel
 	 * @vht_seg0_center_ch: VHT mode Segment0 center channel
@@ -6398,6 +6411,7 @@ union wpa_event_data {
 	 */
 	struct acs_selected_channels {
 		unsigned int pri_freq;
+		unsigned int pri_freq_khz;
 		unsigned int sec_freq;
 		u8 edmg_channel;
 		u8 vht_seg0_center_ch;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4db29f1d5..92f5aa728 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4728,6 +4728,15 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 	    nl80211_put_dtim_period(msg, params->dtim_period) ||
 	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
 		goto fail;
+
+	if (is_s1g_freq(params->freq->freq_khz)) {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+				KHZ_TO_MHZ(params->freq->freq_khz)) ||
+			nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
+				    KHZ_TO_S1G_OFFSET(params->freq->freq_khz)))
+			goto fail;
+	}
+
 	if (params->proberesp && params->proberesp_len) {
 		wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
 			    params->proberesp, params->proberesp_len);
@@ -5057,8 +5066,20 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
 	u8 channel;
 
 	wpa_printf(MSG_DEBUG, "  * freq=%d", freq->freq);
-	if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
-		return -ENOBUFS;
+	if (is_s1g_freq(freq->freq_khz)) {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+		    KHZ_TO_MHZ(freq->freq_khz)))
+			return -ENOBUFS;
+		wpa_printf(MSG_DEBUG, "  * freq_offset=%d",
+			   KHZ_TO_S1G_OFFSET(freq->freq_khz));
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_OFFSET,
+			        KHZ_TO_S1G_OFFSET(freq->freq_khz)))
+			return -ENOBUFS;
+	} else {
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
+			return -ENOBUFS;
+	}
+
 
 	wpa_printf(MSG_DEBUG, "  * eht_enabled=%d", freq->eht_enabled);
 	wpa_printf(MSG_DEBUG, "  * he_enabled=%d", freq->he_enabled);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 53b50045c..7349567cd 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1638,6 +1638,8 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
 
 	os_memset(chan, 0, sizeof(*chan));
 	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+	chan->freq_khz = MHZ_TO_KHZ(chan->freq) +
+		nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_OFFSET]);
 	chan->flag = 0;
 	chan->allowed_bw = ~0;
 	chan->dfs_cac_ms = 0;
@@ -2120,7 +2122,10 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
 	for (m = 0; m < *num_modes; m++) {
 		if (!modes[m].num_channels)
 			continue;
-		if (modes[m].channels[0].freq < 2000) {
+		if (modes[m].channels[0].freq_khz < 1000000 &&
+			modes[m].channels[0].freq_khz > 0){
+			modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+		} else if (modes[m].channels[0].freq < 2000) {
 			modes[m].num_channels = 0;
 			continue;
 		} else if (modes[m].channels[0].freq < 4000) {
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index e3fcb4402..a48c8f4c7 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -992,8 +992,8 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
 
 static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
 				 struct nlattr *ifindex, struct nlattr *link,
-				 struct nlattr *freq, struct nlattr *type,
-				 struct nlattr *bw, struct nlattr *cf1,
+				 struct nlattr *freq, struct nlattr *freq_off,
+				 struct nlattr *type, struct nlattr *bw, struct nlattr *cf1,
 				 struct nlattr *cf2, int finished)
 {
 	struct i802_bss *bss;
@@ -1047,6 +1047,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
 
 	os_memset(&data, 0, sizeof(data));
 	data.ch_switch.freq = nla_get_u32(freq);
+	data.ch_switch.freq_khz = MHZ_TO_KHZ(data.ch_switch.freq) +
+		nla_get_u32(freq_off);
 	data.ch_switch.ht_enabled = ht_enabled;
 	data.ch_switch.ch_offset = chan_offset;
 	if (bw)
@@ -1401,7 +1403,8 @@ static void mlme_event_unprot_beacon(struct wpa_driver_nl80211_data *drv,
 static void mlme_event(struct i802_bss *bss,
 		       enum nl80211_commands cmd, struct nlattr *frame,
 		       struct nlattr *addr, struct nlattr *timed_out,
-		       struct nlattr *freq, struct nlattr *ack,
+		       struct nlattr *freq, struct nlattr *freq_offset,
+		       struct nlattr *ack,
 		       struct nlattr *cookie, struct nlattr *sig,
 		       struct nlattr *wmm, struct nlattr *req_ie)
 {
@@ -3548,7 +3551,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 	case NL80211_CMD_UNPROT_DISASSOCIATE:
 		mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
 			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
-			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+			   tb[NL80211_ATTR_WIPHY_FREQ],
+			   tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
+			   tb[NL80211_ATTR_ACK],
 			   tb[NL80211_ATTR_COOKIE],
 			   tb[NL80211_ATTR_RX_SIGNAL_DBM],
 			   tb[NL80211_ATTR_STA_WME],
@@ -3576,6 +3581,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 				     tb[NL80211_ATTR_IFINDEX],
 				     tb[NL80211_ATTR_MLO_LINK_ID],
 				     tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
 				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
 				     tb[NL80211_ATTR_CHANNEL_WIDTH],
 				     tb[NL80211_ATTR_CENTER_FREQ1],
@@ -3587,6 +3593,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 				     tb[NL80211_ATTR_IFINDEX],
 				     tb[NL80211_ATTR_MLO_LINK_ID],
 				     tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
 				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
 				     tb[NL80211_ATTR_CHANNEL_WIDTH],
 				     tb[NL80211_ATTR_CENTER_FREQ1],
@@ -3775,7 +3782,9 @@ int process_bss_event(struct nl_msg *msg, void *arg)
 	case NL80211_CMD_FRAME_TX_STATUS:
 		mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
 			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
-			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+			   tb[NL80211_ATTR_WIPHY_FREQ],
+			   tb[NL80211_ATTR_WIPHY_FREQ_OFFSET],
+			   tb[NL80211_ATTR_ACK],
 			   tb[NL80211_ATTR_COOKIE],
 			   tb[NL80211_ATTR_RX_SIGNAL_DBM],
 			   tb[NL80211_ATTR_STA_WME], NULL);
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 653f15f54..fb3fd81e2 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1823,8 +1823,9 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
 #endif /* CONFIG_CTRL_IFACE */
 
 
-void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset, int width, int cf1, int cf2, int finished)
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int freq_khz,
+		       int ht, int offset, int width, int cf1, int cf2,
+		       int finished)
 {
 	struct hostapd_iface *iface = wpa_s->ap_iface;
 
@@ -1833,9 +1834,12 @@ void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
 	if (!iface)
 		return;
 	wpa_s->assoc_freq = freq;
-	if (wpa_s->current_ssid)
+	wpa_s->assoc_freq_khz = freq_khz;
+	if (wpa_s->current_ssid) {
 		wpa_s->current_ssid->frequency = freq;
-	hostapd_event_ch_switch(iface->bss[0], freq, ht,
+		wpa_s->current_ssid->frequency_khz = freq_khz;
+	}
+	hostapd_event_ch_switch(iface->bss[0], freq, freq_khz, ht,
 				offset, width, cf1, cf2, finished);
 }
 
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 865429e96..154203c41 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -72,8 +72,8 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
 int ap_switch_channel(struct wpa_supplicant *wpa_s,
 		      struct csa_settings *settings);
 int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
-void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset, int width, int cf1, int cf2, int finished);
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int freq_khz,
+		       int ht, int offset, int width, int cf1, int cf2, int finished);
 struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
 					     int ndef);
 #ifdef CONFIG_AP
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 18b92b40d..0090c664e 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -524,6 +524,11 @@ struct wpa_ssid {
 	 */
 	int frequency;
 
+	/**
+	 * frequency_khz - Channel frequency in kilohertz (kHz)
+	 */
+	int frequency_khz;
+
 	/**
 	 * enable_edmg - Enable EDMG feature in STA/AP mode
 	 *
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 8f0ed2033..159480093 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -5617,6 +5617,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		    wpa_s->current_ssid->mode ==
 		    WPAS_MODE_P2P_GROUP_FORMATION) {
 			wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+					  data->ch_switch.freq_khz,
 					  data->ch_switch.ht_enabled,
 					  data->ch_switch.ch_offset,
 					  data->ch_switch.ch_width,
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 16530fb74..cd781c09c 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -219,6 +219,7 @@ static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s)
 		    &params->freq,
 		    ifmsh->conf->hw_mode,
 		    ifmsh->freq,
+		    ifmsh->freq_khz,
 		    ifmsh->conf->channel,
 		    ifmsh->conf->enable_edmg,
 		    ifmsh->conf->edmg_channel,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d624f16b8..52291b90d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2959,6 +2959,7 @@ static bool ibss_mesh_select_80_160mhz(struct wpa_supplicant *wpa_s,
 
 skip_80mhz:
 	if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
+				    freq->freq_khz,
 				    freq->channel, ssid->enable_edmg,
 				    ssid->edmg_channel, freq->ht_enabled,
 				    freq->vht_enabled, freq->he_enabled,
@@ -2989,6 +2990,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 	bool is_6ghz;
 
 	freq->freq = ssid->frequency;
+	freq->freq_khz = ssid->frequency_khz;
 
 	if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) {
 		struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid);
@@ -3005,7 +3007,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 	hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
 	for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
 		if (wpa_s->hw.modes[i].mode == hw_mode &&
-		    hw_mode_get_channel(&wpa_s->hw.modes[i], freq->freq,
+		    hw_mode_get_channel(&wpa_s->hw.modes[i], freq->freq, freq->freq_khz,
 					NULL) != NULL) {
 			mode = &wpa_s->hw.modes[i];
 			break;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 61d274a05..0a48350e2 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -685,6 +685,7 @@ struct wpa_supplicant {
 	struct wpa_bss *current_bss;
 	int ap_ies_from_associnfo;
 	unsigned int assoc_freq;
+	unsigned int assoc_freq_khz;
 	u8 ap_mld_addr[ETH_ALEN];
 	u8 mlo_assoc_link_id;
 	u16 valid_links; /* bitmap of valid MLO link IDs */
-- 
2.34.1


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux