summaryrefslogtreecommitdiffstats
path: root/net/caif/cfcnfg.c
diff options
context:
space:
mode:
authorSjur Braendeland <sjur.brandeland@stericsson.com>2010-04-28 08:54:37 +0000
committerDavid S. Miller <davem@davemloft.net>2010-04-28 12:55:13 -0700
commit8d545c8f958f5f433c50a00762ce1f231ed56eee (patch)
treef5688212d86c0bc6bf0ba8b02f57fca77de3145e /net/caif/cfcnfg.c
parent5b2086567503f9b55136642031ec0067319f58e0 (diff)
downloadlinux-8d545c8f958f5f433c50a00762ce1f231ed56eee.tar.bz2
caif: Disconnect without waiting for response
Changes: o Function cfcnfg_disconn_adapt_layer is changed to do asynchronous disconnect, not waiting for any response from the modem. Due to this the function cfcnfg_linkdestroy_rsp does nothing anymore. o Because disconnect may take down a connection before a connect response is received the function cfcnfg_linkup_rsp is checking if the client is still waiting for the response, if not a disconnect request is sent to the modem. o cfctrl is no longer keeping track of pending disconnect requests. o Added function cfctrl_cancel_req, which is used for deleting a pending connect request if disconnect is done before connect response is received. o Removed unused function cfctrl_insert_req2 o Added better handling of connect reject from modem. Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/caif/cfcnfg.c')
-rw-r--r--net/caif/cfcnfg.c155
1 files changed, 45 insertions, 110 deletions
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index f94f3dfe85c1..471c62939fad 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -54,8 +54,7 @@ struct cfcnfg {
static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
enum cfctrl_srv serv, u8 phyid,
struct cflayer *adapt_layer);
-static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id,
- struct cflayer *client_layer);
+static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
struct cflayer *adapt_layer);
static void cfctrl_resp_func(void);
@@ -175,73 +174,65 @@ int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
return 0;
}
-/*
- * NOTE: What happens on destroy failure:
- * 1a) No response - Too early
- * This will not happen because enumerate has already
- * completed.
- * 1b) No response - FATAL
- * Not handled, but this should be a CAIF PROTOCOL ERROR
- * Modem error, response is really expected - this
- * case is not really handled.
- * 2) O/E-bit indicate error
- * Ignored - this link is destroyed anyway.
- * 3) Not able to match on request
- * Not handled, but this should be a CAIF PROTOCOL ERROR
- * 4) Link-Error - (no response)
- * Not handled, but this should be a CAIF PROTOCOL ERROR
- */
int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
{
u8 channel_id = 0;
int ret = 0;
+ struct cflayer *servl = NULL;
struct cfcnfg_phyinfo *phyinfo = NULL;
u8 phyid = 0;
-
caif_assert(adap_layer != NULL);
channel_id = adap_layer->id;
- if (channel_id == 0) {
+ if (adap_layer->dn == NULL || channel_id == 0) {
pr_err("CAIF: %s():adap_layer->id is 0\n", __func__);
ret = -ENOTCONN;
goto end;
}
-
- if (adap_layer->dn == NULL) {
- pr_err("CAIF: %s():adap_layer->dn is NULL\n", __func__);
- ret = -ENODEV;
- goto end;
- }
-
- if (adap_layer->dn != NULL)
- phyid = cfsrvl_getphyid(adap_layer->dn);
-
- phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
- if (phyinfo == NULL) {
- pr_warning("CAIF: %s(): No interface to send disconnect to\n",
- __func__);
- ret = -ENODEV;
+ servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
+ if (servl == NULL)
goto end;
- }
-
- if (phyinfo->id != phyid
- || phyinfo->phy_layer->id != phyid
- || phyinfo->frm_layer->id != phyid) {
-
- pr_err("CAIF: %s(): Inconsistency in phy registration\n",
- __func__);
+ layer_set_up(servl, NULL);
+ ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
+ if (servl == NULL) {
+ pr_err("CAIF: %s(): PROTOCOL ERROR "
+ "- Error removing service_layer Channel_Id(%d)",
+ __func__, channel_id);
ret = -EINVAL;
goto end;
}
+ caif_assert(channel_id == servl->id);
+ if (adap_layer->dn != NULL) {
+ phyid = cfsrvl_getphyid(adap_layer->dn);
- ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
-
-end:
+ phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
+ if (phyinfo == NULL) {
+ pr_warning("CAIF: %s(): "
+ "No interface to send disconnect to\n",
+ __func__);
+ ret = -ENODEV;
+ goto end;
+ }
+ if (phyinfo->id != phyid ||
+ phyinfo->phy_layer->id != phyid ||
+ phyinfo->frm_layer->id != phyid) {
+ pr_err("CAIF: %s(): "
+ "Inconsistency in phy registration\n",
+ __func__);
+ ret = -EINVAL;
+ goto end;
+ }
+ }
if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
phyinfo->phy_layer != NULL &&
phyinfo->phy_layer->modemcmd != NULL) {
phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
_CAIF_MODEMCMD_PHYIF_USELESS);
}
+end:
+ cfsrvl_put(servl);
+ cfctrl_cancel_req(cnfg->ctrl, adap_layer);
+ if (adap_layer->ctrlcmd != NULL)
+ adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
return ret;
}
@@ -254,69 +245,11 @@ void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
}
EXPORT_SYMBOL(cfcnfg_release_adap_layer);
-static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id,
- struct cflayer *client_layer)
+static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
{
- struct cfcnfg *cnfg = container_obj(layer);
- struct cflayer *servl;
-
- /*
- * 1) Remove service from the MUX layer. The MUX must
- * guarante that no more payload sent "upwards" (receive)
- */
- servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
-
- if (servl == NULL) {
- pr_err("CAIF: %s(): PROTOCOL ERROR "
- "- Error removing service_layer Channel_Id(%d)",
- __func__, channel_id);
- return;
- }
- caif_assert(channel_id == servl->id);
-
- if (servl != client_layer && servl->up != client_layer) {
- pr_err("CAIF: %s(): Error removing service_layer "
- "Channel_Id(%d) %p %p",
- __func__, channel_id, (void *) servl,
- (void *) client_layer);
- return;
- }
-
- /*
- * 2) DEINIT_RSP must guarantee that no more packets are transmitted
- * from client (adap_layer) when it returns.
- */
-
- if (servl->ctrlcmd == NULL) {
- pr_err("CAIF: %s(): Error servl->ctrlcmd == NULL", __func__);
- return;
- }
-
- servl->ctrlcmd(servl, CAIF_CTRLCMD_DEINIT_RSP, 0);
-
- /* 3) It is now safe to destroy the service layer. */
- cfservl_destroy(servl);
}
-/*
- * NOTE: What happens on linksetup failure:
- * 1a) No response - Too early
- * This will not happen because enumerate is secured
- * before using interface.
- * 1b) No response - FATAL
- * Not handled, but this should be a CAIF PROTOCOL ERROR
- * Modem error, response is really expected - this case is
- * not really handled.
- * 2) O/E-bit indicate error
- * Handled in cnfg_reject_rsp
- * 3) Not able to match on request
- * Not handled, but this should be a CAIF PROTOCOL ERROR
- * 4) Link-Error - (no response)
- * Not handled, but this should be a CAIF PROTOCOL ERROR
- */
-
-int
-cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
+int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
struct cfctrl_link_param *param,
struct cflayer *adap_layer)
{
@@ -346,8 +279,7 @@ cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
param->phyid);
/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
cfctrl_enum_req(cnfg->ctrl, param->phyid);
- cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
- return 0;
+ return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
}
EXPORT_SYMBOL(cfcnfg_add_adaptation_layer);
@@ -367,8 +299,10 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
struct cflayer *servicel = NULL;
struct cfcnfg_phyinfo *phyinfo;
if (adapt_layer == NULL) {
- pr_err("CAIF: %s(): PROTOCOL ERROR "
- "- LinkUp Request/Response did not match\n", __func__);
+ pr_debug("CAIF: %s(): link setup response "
+ "but no client exist, send linkdown back\n",
+ __func__);
+ cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
return;
}
@@ -424,6 +358,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
layer_set_up(servicel, adapt_layer);
layer_set_dn(adapt_layer, servicel);
+ cfsrvl_get(servicel);
servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
}