From 72044390f342d8ad5846ef163f54f54f61b996f8 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 10 Jul 2010 10:19:34 -0700 Subject: [PATCH] P2P: Add support for cross connection If enabled, cross connection allows GO to forward IPv4 packets using masquerading NAT from the P2P clients in the group to an uplink WLAN connection. This is disabled by default and can be enabled with "wpa_cli p2p_set cross_connect 1" on the P2P device interface. --- src/common/wpa_ctrl.h | 2 + src/p2p/p2p.c | 22 +++- src/p2p/p2p.h | 14 +++ src/p2p/p2p_go_neg.c | 18 +++- src/p2p/p2p_group.c | 2 + src/p2p/p2p_i.h | 2 + src/p2p/p2p_parse.c | 15 +++ wpa_supplicant/ctrl_iface.c | 3 + wpa_supplicant/examples/p2p-action.sh | 21 ++++ wpa_supplicant/notify.c | 8 ++ wpa_supplicant/p2p_supplicant.c | 142 ++++++++++++++++++++++++++ wpa_supplicant/p2p_supplicant.h | 3 + wpa_supplicant/wpa_cli.c | 4 + wpa_supplicant/wpa_supplicant.c | 16 +++ wpa_supplicant/wpa_supplicant_i.h | 22 ++++ 15 files changed, 289 insertions(+), 5 deletions(-) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 88412ba71..b70cf7a37 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -101,6 +101,8 @@ extern "C" { #define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE " #define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED " #define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED " +#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE " +#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE " /* parameters: */ #define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN " /* parameters: */ diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 9fc6abff6..86261cac2 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1612,6 +1612,7 @@ static int p2p_assoc_req_ie_wlan_ap(struct p2p_data *p2p, const u8 *bssid, u8 *lpos; size_t tmplen; int res; + u8 group_capab; if (p2p_ie == NULL) return 0; /* WLAN AP is not a P2P manager */ @@ -1627,7 +1628,15 @@ static int p2p_assoc_req_ie_wlan_ap(struct p2p_data *p2p, const u8 *bssid, return -1; lpos = p2p_buf_add_ie_hdr(tmp); - p2p_buf_add_capability(tmp, p2p->dev_capab, 0); + group_capab = 0; + if (p2p->num_groups > 0) { + group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; + if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && + (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) && + p2p->cross_connect) + group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; + } + p2p_buf_add_capability(tmp, p2p->dev_capab, group_capab); if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED)) p2p_buf_add_p2p_interface(tmp, p2p); @@ -2960,3 +2969,14 @@ void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr) wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Enable peer " "filter for " MACSTR, MAC2STR(p2p->peer_filter)); } + + +void p2p_set_cross_connect(struct p2p_data *p2p, int enabled) +{ + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Cross connection %s", + enabled ? "enabled" : "disabled"); + if (p2p->cross_connect == enabled) + return; + p2p->cross_connect = enabled; + /* TODO: may need to tear down any action group where we are GO(?) */ +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index e108172a0..8be8aead4 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1170,6 +1170,13 @@ int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params); */ u8 p2p_get_group_capab(const struct wpabuf *p2p_ie); +/** + * p2p_get_cross_connect_disallowed - Does WLAN AP disallows cross connection + * @p2p_ie: P2P IE(s) contents + * Returns: 0 if cross connection is allow, 1 if not + */ +int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie); + /** * p2p_get_go_dev_addr - Get P2P Device Address from P2P IE data * @p2p_ie: P2P IE(s) contents @@ -1216,4 +1223,11 @@ int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr); +/** + * p2p_set_cross_connect - Set cross connection capability + * @p2p: P2P module context from p2p_init() + * @enabled: Whether cross connection will be enabled + */ +void p2p_set_cross_connect(struct p2p_data *p2p, int enabled); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 4686007db..227b47c80 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -158,6 +158,8 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, group_capab = 0; if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (p2p->cross_connect) + group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; p2p_buf_add_capability(buf, p2p->dev_capab, group_capab); p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | p2p->next_tie_breaker); @@ -242,8 +244,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_status(buf, status); group_capab = 0; - if (peer && (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)) - group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer && peer->go_state == LOCAL_GO) { + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (p2p->cross_connect) + group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; + } p2p_buf_add_capability(buf, p2p->dev_capab, group_capab); p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker); p2p_buf_add_config_timeout(buf, 100, 20); @@ -631,8 +637,12 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_status(buf, status); group_capab = 0; - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) - group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer->go_state == LOCAL_GO) { + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (p2p->cross_connect) + group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; + } p2p_buf_add_capability(buf, p2p->dev_capab, group_capab); if (go || resp_chan == NULL) p2p_buf_add_operating_channel(buf, p2p->cfg->country, diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index dd938d6ed..17837cbae 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -145,6 +145,8 @@ static void p2p_group_add_common_ies(struct p2p_group *group, group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; if (group->group_formation) group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION; + if (group->p2p->cross_connect) + group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; p2p_buf_add_capability(ie, dev_capab, group_capab); } diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 5c9d0ebda..f349bc7b6 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -365,6 +365,8 @@ struct p2p_data { unsigned int ext_listen_interval_usec; u8 peer_filter[ETH_ALEN]; + + int cross_connect; }; /** diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c index 07b9b51d7..b82848e49 100644 --- a/src/p2p/p2p_parse.c +++ b/src/p2p/p2p_parse.c @@ -650,6 +650,21 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end) } +int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie) +{ + struct p2p_message msg; + + os_memset(&msg, 0, sizeof(msg)); + if (p2p_parse_p2p_ie(p2p_ie, &msg)) + return 0; + + if (!msg.manageability) + return 0; + + return !(msg.capability[0] & P2P_MAN_CROSS_CONNECTIION_PERMITTED); +} + + u8 p2p_get_group_capab(const struct wpabuf *p2p_ie) { struct p2p_message msg; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 835575747..739b9e903 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2476,6 +2476,9 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return 0; } + if (os_strcmp(cmd, "cross_connect") == 0) + return wpas_p2p_set_cross_connect(wpa_s, atoi(param)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); diff --git a/wpa_supplicant/examples/p2p-action.sh b/wpa_supplicant/examples/p2p-action.sh index ee645cb4e..38fd8d65d 100755 --- a/wpa_supplicant/examples/p2p-action.sh +++ b/wpa_supplicant/examples/p2p-action.sh @@ -54,3 +54,24 @@ if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then ifconfig $GIFNAME 0.0.0.0 fi fi + +if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then + GIFNAME=$3 + UPLINK=$4 + # enable NAT/masquarade $GIFNAME -> $UPLINK + iptables -P FORWARD DROP + iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE + iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT + iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT + sysctl net.ipv4.ip_forward=1 +fi + +if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then + GIFNAME=$3 + UPLINK=$4 + # disable NAT/masquarade $GIFNAME -> $UPLINK + sysctl net.ipv4.ip_forward=0 + iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE + iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT + iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT +fi diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index ac65b4f0d..c9a1b4b1b 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -24,6 +24,7 @@ #include "dbus/dbus_new.h" #include "driver_i.h" #include "scan.h" +#include "p2p_supplicant.h" #include "notify.h" int wpas_notify_supplicant_initialized(struct wpa_global *global) @@ -81,6 +82,13 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, /* notify the new DBus API */ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE); + +#ifdef CONFIG_P2P + if (new_state == WPA_COMPLETED) + wpas_p2p_notif_connected(wpa_s); + else if (new_state < WPA_ASSOCIATED) + wpas_p2p_notif_disconnected(wpa_s); +#endif /* CONFIG_P2P */ } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index b25765432..cbe1c4f26 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -45,6 +45,7 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, const u8 *dev_addr, enum p2p_wps_method wps_method); static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s); +static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s); static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, @@ -201,6 +202,12 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s) gtype = "client"; } else gtype = "GO"; + if (wpa_s->cross_connect_in_use) { + wpa_s->cross_connect_in_use = 0; + wpa_msg(wpa_s->parent, MSG_INFO, + P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", + wpa_s->ifname, wpa_s->cross_connect_uplink); + } wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s", wpa_s->ifname, gtype); if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { @@ -441,6 +448,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, "%s GO ssid=\"%s\" psk=%s go_dev_addr=" MACSTR "%s", wpa_s->ifname, ssid_txt, psk, MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : ""); + wpas_p2p_cross_connect_setup(wpa_s); } else { wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s GO ssid=\"%s\" passphrase=\"%s\" go_dev_addr=" @@ -449,6 +457,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, ssid && ssid->passphrase ? ssid->passphrase : "", MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : ""); + wpas_p2p_cross_connect_setup(wpa_s); } if (persistent) @@ -717,6 +726,7 @@ static void p2p_go_configured(void *ctx, void *data) wpas_p2p_store_persistent_group( wpa_s->parent, ssid, wpa_s->parent->own_addr); + wpas_p2p_cross_connect_setup(wpa_s); return; } @@ -3307,3 +3317,135 @@ int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start, return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start, duration); } + + +int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled) +{ + if (wpa_s->global->p2p_disabled) + return -1; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return -1; + + wpa_s->global->cross_connection = enabled; + p2p_set_cross_connect(wpa_s->global->p2p, enabled); + + if (!enabled) { + struct wpa_supplicant *iface; + + for (iface = wpa_s->global->ifaces; iface; iface = iface->next) + { + if (iface->cross_connect_enabled == 0) + continue; + + iface->cross_connect_enabled = 0; + iface->cross_connect_in_use = 0; + wpa_msg(iface->parent, MSG_INFO, + P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", + iface->ifname, iface->cross_connect_uplink); + } + } + + return 0; +} + + +static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink) +{ + struct wpa_supplicant *iface; + + if (!uplink->global->cross_connection) + return; + + for (iface = uplink->global->ifaces; iface; iface = iface->next) { + if (!iface->cross_connect_enabled) + continue; + if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) != + 0) + continue; + if (iface->ap_iface == NULL) + continue; + if (iface->cross_connect_in_use) + continue; + + iface->cross_connect_in_use = 1; + wpa_msg(iface->parent, MSG_INFO, + P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", + iface->ifname, iface->cross_connect_uplink); + } +} + + +static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink) +{ + struct wpa_supplicant *iface; + + for (iface = uplink->global->ifaces; iface; iface = iface->next) { + if (!iface->cross_connect_enabled) + continue; + if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) != + 0) + continue; + if (!iface->cross_connect_in_use) + continue; + + wpa_msg(iface->parent, MSG_INFO, + P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", + iface->ifname, iface->cross_connect_uplink); + iface->cross_connect_in_use = 0; + } +} + + +void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->ap_iface || wpa_s->current_ssid == NULL || + wpa_s->current_ssid->mode != WPAS_MODE_INFRA || + wpa_s->cross_connect_disallowed) + wpas_p2p_disable_cross_connect(wpa_s); + else + wpas_p2p_enable_cross_connect(wpa_s); +} + + +void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s) +{ + wpas_p2p_disable_cross_connect(wpa_s); +} + + +static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s) +{ + struct wpa_supplicant *iface; + + if (!wpa_s->global->cross_connection) + return; + + for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { + if (iface == wpa_s) + continue; + if (iface->drv_flags & + WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE) + continue; + if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) + continue; + + wpa_s->cross_connect_enabled = 1; + os_strlcpy(wpa_s->cross_connect_uplink, iface->ifname, + sizeof(wpa_s->cross_connect_uplink)); + wpa_printf(MSG_DEBUG, "P2P: Enable cross connection from " + "%s to %s whenever uplink is available", + wpa_s->ifname, wpa_s->cross_connect_uplink); + + if (iface->ap_iface || iface->current_ssid == NULL || + iface->current_ssid->mode != WPAS_MODE_INFRA || + iface->cross_connect_disallowed || + iface->wpa_state != WPA_COMPLETED) + break; + + wpa_s->cross_connect_in_use = 1; + wpa_msg(wpa_s->parent, MSG_INFO, + P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", + wpa_s->ifname, wpa_s->cross_connect_uplink); + break; + } +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index e1578fca9..11674e0db 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -108,5 +108,8 @@ void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, void wpas_p2p_update_config(struct wpa_supplicant *wpa_s); int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start, int duration); +int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled); +void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s); +void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s); #endif /* P2P_SUPPLICANT_H */ diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index d062fab1d..af6377783 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -2548,6 +2548,10 @@ static void wpa_cli_action_process(const char *msg) wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); + } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) { + wpa_cli_exec(action_file, ctrl_ifname, pos); + } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) { + wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, WPA_EVENT_TERMINATING)) { printf("wpa_supplicant is terminating - stop monitoring\n"); wpa_cli_quit = 1; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 177fe5bb5..8536b4558 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -36,6 +36,7 @@ #include "common/wpa_ctrl.h" #include "mlme.h" #include "common/ieee802_11_defs.h" +#include "p2p/p2p.h" #include "blacklist.h" #include "wpas_glue.h" #include "wps_supplicant.h" @@ -1169,6 +1170,21 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, if (res >= 0) wpa_ie_len += res; } + + wpa_s->cross_connect_disallowed = 0; + if (bss) { + struct wpabuf *p2p; + p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE); + if (p2p) { + wpa_s->cross_connect_disallowed = + p2p_get_cross_connect_disallowed(p2p); + wpabuf_free(p2p); + wpa_printf(MSG_DEBUG, "P2P: WLAN AP %s cross " + "connection", + wpa_s->cross_connect_disallowed ? + "disallows" : "allows"); + } + } #endif /* CONFIG_P2P */ wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 534ce942e..fb1b955ff 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -214,6 +214,7 @@ struct wpa_global { struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */ struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */ int p2p_disabled; + int cross_connection; }; @@ -486,6 +487,27 @@ struct wpa_supplicant { int pending_join_wps_method; unsigned int roc_waiting_drv_freq; int force_long_sd; + + /* + * Whether cross connection is disallowed by the AP to which this + * interface is associated (only valid if there is an association). + */ + int cross_connect_disallowed; + + /* + * Whether this P2P group is configured to use cross connection (only + * valid if this is P2P GO interface). The actual cross connect packet + * forwarding may not be configured depending on the uplink status. + */ + int cross_connect_enabled; + + /* Whether cross connection forwarding is in use at the moment. */ + int cross_connect_in_use; + + /* + * Uplink interface name for cross connection + */ + char cross_connect_uplink[100]; #endif /* CONFIG_P2P */ struct wpa_ssid *bgscan_ssid;