]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Move GAS/ANQP build routines to a separate file from P2P
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 27 Sep 2011 14:28:46 +0000 (17:28 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 29 Sep 2011 19:18:46 +0000 (22:18 +0300)
GAS/ANQP is a generic protocol and in no way specific to P2P, so move
routines used to build GAS/ANQP frames to a separate file that can be
shared for other uses than just P2P service discovery.

src/common/gas.c [new file with mode: 0644]
src/common/gas.h [new file with mode: 0644]
src/p2p/p2p_sd.c
wpa_supplicant/Makefile

diff --git a/src/common/gas.c b/src/common/gas.c
new file mode 100644 (file)
index 0000000..c9f6c46
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+
+
+static struct wpabuf *
+gas_build_req(u8 action, u8 dialog_token, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(100 + size);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+       wpabuf_put_u8(buf, action);
+       wpabuf_put_u8(buf, dialog_token);
+
+       return buf;
+}
+
+
+static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+{
+       return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
+                            size);
+}
+
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token)
+{
+       return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
+}
+
+
+static struct wpabuf *
+gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
+              u8 more, u16 comeback_delay, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(100 + size);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+       wpabuf_put_u8(buf, action);
+       wpabuf_put_u8(buf, dialog_token);
+       wpabuf_put_le16(buf, status_code);
+       if (action == WLAN_PA_GAS_COMEBACK_RESP)
+               wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
+       wpabuf_put_le16(buf, comeback_delay);
+
+       return buf;
+}
+
+
+static struct wpabuf *
+gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
+                      size_t size)
+{
+       return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
+                             status_code, 0, 0, comeback_delay, size);
+}
+
+
+static struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+                       u16 comeback_delay, size_t size)
+{
+       return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
+                             status_code, frag_id, more, comeback_delay,
+                             size);
+}
+
+
+/**
+ * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
+ * @buf: Buffer to which the element is added
+ * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
+ * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
+ *
+ *
+ * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
+ * that the maximum limit is determined by the maximum allowable number of
+ * fragments in the GAS Query Response Fragment ID.
+ */
+static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
+                                  u8 pame_bi)
+{
+       /* Advertisement Protocol IE */
+       wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+       wpabuf_put_u8(buf, 2); /* Length */
+       wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+                     (pame_bi ? 0x80 : 0));
+       /* Advertisement Protocol */
+       wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
+}
+
+
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = gas_build_initial_req(dialog_token, 4 + size);
+       if (buf == NULL)
+               return NULL;
+
+       gas_add_adv_proto_anqp(buf, 0, 0);
+
+       wpabuf_put(buf, 2); /* Query Request Length to be filled */
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+                                           u16 comeback_delay, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
+                                    4 + size);
+       if (buf == NULL)
+               return NULL;
+
+       gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+       wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+                                               u16 status_code,
+                                               u16 comeback_delay,
+                                               struct wpabuf *payload)
+{
+       struct wpabuf *buf;
+
+       buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+                                         comeback_delay,
+                                         payload ? wpabuf_len(payload) : 0);
+       if (buf == NULL)
+               return NULL;
+
+       if (payload)
+               wpabuf_put_buf(buf, payload);
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+                                            u8 frag_id, u8 more,
+                                            u16 comeback_delay, size_t size)
+{
+       struct wpabuf *buf;
+
+       buf = gas_build_comeback_resp(dialog_token, status_code,
+                                     frag_id, more, comeback_delay, 4 + size);
+       if (buf == NULL)
+               return NULL;
+
+       gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+       wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+       return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+                                                u16 status_code,
+                                                u8 frag_id, u8 more,
+                                                u16 comeback_delay,
+                                                struct wpabuf *payload)
+{
+       struct wpabuf *buf;
+
+       buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+                                          more, comeback_delay,
+                                          payload ? wpabuf_len(payload) : 0);
+       if (buf == NULL)
+               return NULL;
+
+       if (payload)
+               wpabuf_put_buf(buf, payload);
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+/**
+ * gas_anqp_set_len - Set Query Request/Response Length
+ * @buf: GAS message
+ *
+ * This function is used to update the Query Request/Response Length field once
+ * the payload has been filled.
+ */
+void gas_anqp_set_len(struct wpabuf *buf)
+{
+       u8 action;
+       size_t offset;
+       u8 *len;
+
+       if (buf == NULL || wpabuf_len(buf) < 2)
+               return;
+
+       action = *(wpabuf_head_u8(buf) + 1);
+       switch (action) {
+       case WLAN_PA_GAS_INITIAL_REQ:
+               offset = 3 + 4;
+               break;
+       case WLAN_PA_GAS_INITIAL_RESP:
+               offset = 7 + 4;
+               break;
+       case WLAN_PA_GAS_COMEBACK_RESP:
+               offset = 8 + 4;
+               break;
+       default:
+               return;
+       }
+
+       if (wpabuf_len(buf) < offset + 2)
+               return;
+
+       len = wpabuf_mhead_u8(buf) + offset;
+       WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+/**
+ * gas_anqp_add_element - Add ANQP element header
+ * @buf: GAS message
+ * @info_id: ANQP Info ID
+ * Returns: Pointer to the Length field for gas_anqp_set_element_len()
+ */
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
+{
+       wpabuf_put_le16(buf, info_id);
+       return wpabuf_put(buf, 2); /* Length to be filled */
+}
+
+
+/**
+ * gas_anqp_set_element_len - Update ANQP element Length field
+ * @buf: GAS message
+ * @len_pos: Length field position from gas_anqp_add_element()
+ *
+ * This function is called after the ANQP element payload has been added to the
+ * buffer.
+ */
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
+{
+       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+}
diff --git a/src/common/gas.h b/src/common/gas.h
new file mode 100644 (file)
index 0000000..4a49800
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef GAS_H
+#define GAS_H
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token);
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+                                           u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+                                               u16 status_code,
+                                               u16 comeback_delay,
+                                               struct wpabuf *payload);
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+                                            u8 frag_id, u8 more,
+                                            u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+                                                u16 status_code,
+                                                u8 frag_id, u8 more,
+                                                u16 comeback_delay,
+                                                struct wpabuf *payload);
+void gas_anqp_set_len(struct wpabuf *buf);
+
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
+
+#endif /* GAS_H */
index 1c3738c005a0e5f77f783e924e11a2721bb1b49f..43b3a61c0d5a9c61e1b04ccfbcd8c0fe377e8386 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/gas.h"
 #include "p2p_i.h"
 #include "p2p.h"
 
@@ -90,52 +91,21 @@ static struct wpabuf * p2p_build_sd_query(u16 update_indic,
                                          struct wpabuf *tlvs)
 {
        struct wpabuf *buf;
-       u8 *len_pos, *len_pos2;
+       u8 *len_pos;
 
-       buf = wpabuf_alloc(1000 + wpabuf_len(tlvs));
+       buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
        if (buf == NULL)
                return NULL;
 
-       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-       wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
-       wpabuf_put_u8(buf, 0); /* Dialog Token */
-
-       /* Advertisement Protocol IE */
-       wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-       wpabuf_put_u8(buf, 2); /* Length */
-       wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */
-       /* Advertisement Protocol */
-       wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
-
-       /* Query Request */
-       len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
        /* ANQP Query Request Frame */
-       wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
-       len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+       len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
        wpabuf_put_be24(buf, OUI_WFA);
        wpabuf_put_u8(buf, P2P_OUI_TYPE);
        wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
        wpabuf_put_buf(buf, tlvs);
+       gas_anqp_set_element_len(buf, len_pos);
 
-       WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
-       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
-
-       return buf;
-}
-
-
-static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token)
-{
-       struct wpabuf *buf;
-
-       buf = wpabuf_alloc(3);
-       if (buf == NULL)
-               return NULL;
-
-       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-       wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ);
-       wpabuf_put_u8(buf, dialog_token);
+       gas_anqp_set_len(buf);
 
        return buf;
 }
@@ -146,7 +116,7 @@ static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
 {
        struct wpabuf *req;
 
-       req = p2p_build_gas_comeback_req(dialog_token);
+       req = gas_build_comeback_req(dialog_token);
        if (req == NULL)
                return;
 
@@ -166,43 +136,26 @@ static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
                                             const struct wpabuf *tlvs)
 {
        struct wpabuf *buf;
-       u8 *len_pos, *len_pos2;
+       u8 *len_pos;
 
-       buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0));
+       buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+                                         comeback_delay,
+                                         100 + (tlvs ? wpabuf_len(tlvs) : 0));
        if (buf == NULL)
                return NULL;
 
-       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-       wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
-       wpabuf_put_u8(buf, dialog_token);
-       wpabuf_put_le16(buf, status_code);
-       wpabuf_put_le16(buf, comeback_delay);
-
-       /* Advertisement Protocol IE */
-       wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-       wpabuf_put_u8(buf, 2); /* Length */
-       wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
-       /* Advertisement Protocol */
-       wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
-
-       /* Query Response */
-       len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
        if (tlvs) {
                /* ANQP Query Response Frame */
-               wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
-               len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+               len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
                wpabuf_put_be24(buf, OUI_WFA);
                wpabuf_put_u8(buf, P2P_OUI_TYPE);
                 /* Service Update Indicator */
                wpabuf_put_le16(buf, update_indic);
                wpabuf_put_buf(buf, tlvs);
-
-               WPA_PUT_LE16(len_pos2,
-                            (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
+               gas_anqp_set_element_len(buf, len_pos);
        }
 
-       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+       gas_anqp_set_len(buf);
 
        return buf;
 }
@@ -216,29 +169,12 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
                                                   u16 total_len)
 {
        struct wpabuf *buf;
-       u8 *len_pos;
 
-       buf = wpabuf_alloc(1000 + len);
+       buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+                                          more, 0, 100 + len);
        if (buf == NULL)
                return NULL;
 
-       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-       wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP);
-       wpabuf_put_u8(buf, dialog_token);
-       wpabuf_put_le16(buf, status_code);
-       wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
-       wpabuf_put_le16(buf, 0); /* Comeback Delay */
-
-       /* Advertisement Protocol IE */
-       wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-       wpabuf_put_u8(buf, 2); /* Length */
-       wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
-       /* Advertisement Protocol */
-       wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
-
-       /* Query Response */
-       len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
        if (frag_id == 0) {
                /* ANQP Query Response Frame */
                wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
@@ -250,8 +186,7 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
        }
 
        wpabuf_put_data(buf, data, len);
-
-       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+       gas_anqp_set_len(buf);
 
        return buf;
 }
index 78ce532bf19cc7242523d058d434ed698e160d6b..f28632b00151916693d228f032851ec7f49b86fc 100644 (file)
@@ -201,6 +201,7 @@ OBJS += ../src/p2p/p2p_dev_disc.o
 OBJS += ../src/p2p/p2p_group.o
 OBJS += ../src/ap/p2p_hostapd.o
 CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
 NEED_80211_COMMON=y
 ifdef CONFIG_P2P_STRICT
 CFLAGS += -DCONFIG_P2P_STRICT
@@ -1282,6 +1283,10 @@ CFLAGS += -DCONFIG_BGSCAN
 OBJS += bgscan.o
 endif
 
+ifdef NEED_GAS
+OBJS += ../src/common/gas.o
+endif
+
 OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
 OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
 ifdef CONFIG_AUTHENTICATOR