summaryrefslogtreecommitdiff
path: root/drivers/isdn
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/gigaset/ev-layer.c365
-rw-r--r--drivers/isdn/i4l/isdn_net.c33
-rw-r--r--drivers/isdn/mISDN/socket.c7
3 files changed, 198 insertions, 207 deletions
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index c8ced12fa452..1cfcea62aed9 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -389,22 +389,49 @@ zsau_resp[] =
{NULL, ZSAU_UNKNOWN}
};
-/* retrieve CID from parsed response
- * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
+/* check for and remove fixed string prefix
+ * If s starts with prefix terminated by a non-alphanumeric character,
+ * return pointer to the first character after that, otherwise return NULL.
*/
-static int cid_of_response(char *s)
+static char *skip_prefix(char *s, const char *prefix)
{
- int cid;
- int rc;
-
- if (s[-1] != ';')
- return 0; /* no CID separator */
- rc = kstrtoint(s, 10, &cid);
- if (rc)
- return 0; /* CID not numeric */
- if (cid < 1 || cid > 65535)
- return -1; /* CID out of range */
- return cid;
+ while (*prefix)
+ if (*s++ != *prefix++)
+ return NULL;
+ if (isalnum(*s))
+ return NULL;
+ return s;
+}
+
+/* queue event with CID */
+static void add_cid_event(struct cardstate *cs, int cid, int type,
+ void *ptr, int parameter)
+{
+ unsigned long flags;
+ unsigned next, tail;
+ struct event_t *event;
+
+ gig_dbg(DEBUG_EVENT, "queueing event %d for cid %d", type, cid);
+
+ spin_lock_irqsave(&cs->ev_lock, flags);
+
+ tail = cs->ev_tail;
+ next = (tail + 1) % MAX_EVENTS;
+ if (unlikely(next == cs->ev_head)) {
+ dev_err(cs->dev, "event queue full\n");
+ kfree(ptr);
+ } else {
+ event = cs->events + tail;
+ event->type = type;
+ event->cid = cid;
+ event->ptr = ptr;
+ event->arg = NULL;
+ event->parameter = parameter;
+ event->at_state = NULL;
+ cs->ev_tail = next;
+ }
+
+ spin_unlock_irqrestore(&cs->ev_lock, flags);
}
/**
@@ -417,190 +444,188 @@ static int cid_of_response(char *s)
*/
void gigaset_handle_modem_response(struct cardstate *cs)
{
- unsigned char *argv[MAX_REC_PARAMS + 1];
- int params;
- int i, j;
+ char *eoc, *psep, *ptr;
const struct resp_type_t *rt;
const struct zsau_resp_t *zr;
- int curarg;
- unsigned long flags;
- unsigned next, tail, head;
- struct event_t *event;
- int resp_code;
- int param_type;
- int abort;
- size_t len;
- int cid;
- int rawstring;
-
- len = cs->cbytes;
- if (!len) {
+ int cid, parameter;
+ u8 type, value;
+
+ if (!cs->cbytes) {
/* ignore additional LFs/CRs (M10x config mode or cx100) */
gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[0]);
return;
}
- cs->respdata[len] = 0;
- argv[0] = cs->respdata;
- params = 1;
+ cs->respdata[cs->cbytes] = 0;
+
if (cs->at_state.getstring) {
- /* getstring only allowed without cid at the moment */
+ /* state machine wants next line verbatim */
cs->at_state.getstring = 0;
- rawstring = 1;
- cid = 0;
- } else {
- /* parse line */
- for (i = 0; i < len; i++)
- switch (cs->respdata[i]) {
- case ';':
- case ',':
- case '=':
- if (params > MAX_REC_PARAMS) {
- dev_warn(cs->dev,
- "too many parameters in response\n");
- /* need last parameter (might be CID) */
- params--;
- }
- argv[params++] = cs->respdata + i + 1;
- }
-
- rawstring = 0;
- cid = params > 1 ? cid_of_response(argv[params - 1]) : 0;
- if (cid < 0) {
- gigaset_add_event(cs, &cs->at_state, RSP_INVAL,
- NULL, 0, NULL);
- return;
- }
+ ptr = kstrdup(cs->respdata, GFP_ATOMIC);
+ gig_dbg(DEBUG_EVENT, "string==%s", ptr ? ptr : "NULL");
+ add_cid_event(cs, 0, RSP_STRING, ptr, 0);
+ return;
+ }
- for (j = 1; j < params; ++j)
- argv[j][-1] = 0;
+ /* look up response type */
+ for (rt = resp_type; rt->response; ++rt) {
+ eoc = skip_prefix(cs->respdata, rt->response);
+ if (eoc)
+ break;
+ }
+ if (!rt->response) {
+ add_cid_event(cs, 0, RSP_NONE, NULL, 0);
+ gig_dbg(DEBUG_EVENT, "unknown modem response: '%s'\n",
+ cs->respdata);
+ return;
+ }
- gig_dbg(DEBUG_EVENT, "CMD received: %s", argv[0]);
- if (cid) {
- --params;
- gig_dbg(DEBUG_EVENT, "CID: %s", argv[params]);
- }
- gig_dbg(DEBUG_EVENT, "available params: %d", params - 1);
- for (j = 1; j < params; j++)
- gig_dbg(DEBUG_EVENT, "param %d: %s", j, argv[j]);
+ /* check for CID */
+ psep = strrchr(cs->respdata, ';');
+ if (psep &&
+ !kstrtoint(psep + 1, 10, &cid) &&
+ cid >= 1 && cid <= 65535) {
+ /* valid CID: chop it off */
+ *psep = 0;
+ } else {
+ /* no valid CID: leave unchanged */
+ cid = 0;
}
- spin_lock_irqsave(&cs->ev_lock, flags);
- head = cs->ev_head;
- tail = cs->ev_tail;
+ gig_dbg(DEBUG_EVENT, "CMD received: %s", cs->respdata);
+ if (cid)
+ gig_dbg(DEBUG_EVENT, "CID: %d", cid);
- abort = 1;
- curarg = 0;
- while (curarg < params) {
- next = (tail + 1) % MAX_EVENTS;
- if (unlikely(next == head)) {
- dev_err(cs->dev, "event queue full\n");
- break;
- }
+ switch (rt->type) {
+ case RT_NOTHING:
+ /* check parameter separator */
+ if (*eoc)
+ goto bad_param; /* extra parameter */
- event = cs->events + tail;
- event->at_state = NULL;
- event->cid = cid;
- event->ptr = NULL;
- event->arg = NULL;
- tail = next;
+ add_cid_event(cs, cid, rt->resp_code, NULL, 0);
+ break;
- if (rawstring) {
- resp_code = RSP_STRING;
- param_type = RT_STRING;
- } else {
- for (rt = resp_type; rt->response; ++rt)
- if (!strcmp(argv[curarg], rt->response))
+ case RT_RING:
+ /* check parameter separator */
+ if (!*eoc)
+ eoc = NULL; /* no parameter */
+ else if (*eoc++ != ',')
+ goto bad_param;
+
+ add_cid_event(cs, 0, rt->resp_code, NULL, cid);
+
+ /* process parameters as individual responses */
+ while (eoc) {
+ /* look up parameter type */
+ psep = NULL;
+ for (rt = resp_type; rt->response; ++rt) {
+ psep = skip_prefix(eoc, rt->response);
+ if (psep)
break;
+ }
- if (!rt->response) {
- event->type = RSP_NONE;
- gig_dbg(DEBUG_EVENT,
- "unknown modem response: '%s'\n",
- argv[curarg]);
- break;
+ /* all legal parameters are of type RT_STRING */
+ if (!psep || rt->type != RT_STRING) {
+ dev_warn(cs->dev,
+ "illegal RING parameter: '%s'\n",
+ eoc);
+ return;
}
- resp_code = rt->resp_code;
- param_type = rt->type;
- ++curarg;
- }
+ /* skip parameter value separator */
+ if (*psep++ != '=')
+ goto bad_param;
- event->type = resp_code;
+ /* look up end of parameter */
+ eoc = strchr(psep, ',');
+ if (eoc)
+ *eoc++ = 0;
- switch (param_type) {
- case RT_NOTHING:
- break;
- case RT_RING:
- if (!cid) {
- dev_err(cs->dev,
- "received RING without CID!\n");
- event->type = RSP_INVAL;
- abort = 1;
- } else {
- event->cid = 0;
- event->parameter = cid;
- abort = 0;
- }
+ /* retrieve parameter value */
+ ptr = kstrdup(psep, GFP_ATOMIC);
+
+ /* queue event */
+ add_cid_event(cs, cid, rt->resp_code, ptr, 0);
+ }
+ break;
+
+ case RT_ZSAU:
+ /* check parameter separator */
+ if (!*eoc) {
+ /* no parameter */
+ add_cid_event(cs, cid, rt->resp_code, NULL, ZSAU_NONE);
break;
- case RT_ZSAU:
- if (curarg >= params) {
- event->parameter = ZSAU_NONE;
+ }
+ if (*eoc++ != '=')
+ goto bad_param;
+
+ /* look up parameter value */
+ for (zr = zsau_resp; zr->str; ++zr)
+ if (!strcmp(eoc, zr->str))
break;
- }
- for (zr = zsau_resp; zr->str; ++zr)
- if (!strcmp(argv[curarg], zr->str))
- break;
- event->parameter = zr->code;
- if (!zr->str)
- dev_warn(cs->dev,
- "%s: unknown parameter %s after ZSAU\n",
- __func__, argv[curarg]);
- ++curarg;
- break;
- case RT_STRING:
- if (curarg < params) {
- event->ptr = kstrdup(argv[curarg], GFP_ATOMIC);
- if (!event->ptr)
- dev_err(cs->dev, "out of memory\n");
- ++curarg;
- }
- gig_dbg(DEBUG_EVENT, "string==%s",
- event->ptr ? (char *) event->ptr : "NULL");
- break;
- case RT_ZCAU:
- event->parameter = -1;
- if (curarg + 1 < params) {
- u8 type, value;
-
- i = kstrtou8(argv[curarg++], 16, &type);
- j = kstrtou8(argv[curarg++], 16, &value);
- if (i == 0 && j == 0)
- event->parameter = (type << 8) | value;
- } else
- curarg = params - 1;
- break;
- case RT_NUMBER:
- if (curarg >= params ||
- kstrtoint(argv[curarg++], 10, &event->parameter))
- event->parameter = -1;
- gig_dbg(DEBUG_EVENT, "parameter==%d", event->parameter);
- break;
+ if (!zr->str)
+ goto bad_param;
+
+ add_cid_event(cs, cid, rt->resp_code, NULL, zr->code);
+ break;
+
+ case RT_STRING:
+ /* check parameter separator */
+ if (*eoc++ != '=')
+ goto bad_param;
+
+ /* retrieve parameter value */
+ ptr = kstrdup(eoc, GFP_ATOMIC);
+
+ /* queue event */
+ add_cid_event(cs, cid, rt->resp_code, ptr, 0);
+ break;
+
+ case RT_ZCAU:
+ /* check parameter separators */
+ if (*eoc++ != '=')
+ goto bad_param;
+ psep = strchr(eoc, ',');
+ if (!psep)
+ goto bad_param;
+ *psep++ = 0;
+
+ /* decode parameter values */
+ if (kstrtou8(eoc, 16, &type) || kstrtou8(psep, 16, &value)) {
+ *--psep = ',';
+ goto bad_param;
}
+ parameter = (type << 8) | value;
- if (resp_code == RSP_ZDLE)
- cs->dle = event->parameter;
+ add_cid_event(cs, cid, rt->resp_code, NULL, parameter);
+ break;
- if (abort)
- break;
- }
+ case RT_NUMBER:
+ /* check parameter separator */
+ if (*eoc++ != '=')
+ goto bad_param;
- cs->ev_tail = tail;
- spin_unlock_irqrestore(&cs->ev_lock, flags);
+ /* decode parameter value */
+ if (kstrtoint(eoc, 10, &parameter))
+ goto bad_param;
+
+ /* special case ZDLE: set flag before queueing event */
+ if (rt->resp_code == RSP_ZDLE)
+ cs->dle = parameter;
- if (curarg != params)
- gig_dbg(DEBUG_EVENT,
- "invalid number of processed parameters: %d/%d",
- curarg, params);
+ add_cid_event(cs, cid, rt->resp_code, NULL, parameter);
+ break;
+
+bad_param:
+ /* parameter unexpected, incomplete or malformed */
+ dev_warn(cs->dev, "bad parameter in response '%s'\n",
+ cs->respdata);
+ add_cid_event(cs, cid, rt->resp_code, NULL, -1);
+ break;
+
+ default:
+ dev_err(cs->dev, "%s: internal error on '%s'\n",
+ __func__, cs->respdata);
+ }
}
EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 94affa5e6f28..546b7e81161d 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1951,38 +1951,6 @@ static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
return len;
}
-/* We don't need to send arp, because we have point-to-point connections. */
-static int
-isdn_net_rebuild_header(struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- isdn_net_local *lp = netdev_priv(dev);
- int ret = 0;
-
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
- struct ethhdr *eth = (struct ethhdr *) skb->data;
-
- /*
- * Only ARP/IP is currently supported
- */
-
- if (eth->h_proto != htons(ETH_P_IP)) {
- printk(KERN_WARNING
- "isdn_net: %s don't know how to resolve type %d addresses?\n",
- dev->name, (int) eth->h_proto);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return 0;
- }
- /*
- * Try to get ARP to resolve the header.
- */
-#ifdef CONFIG_INET
- ret = arp_find(eth->h_dest, skb);
-#endif
- }
- return ret;
-}
-
static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
__be16 type)
{
@@ -2005,7 +1973,6 @@ static void isdn_header_cache_update(struct hh_cache *hh,
static const struct header_ops isdn_header_ops = {
.create = isdn_net_header,
- .rebuild = isdn_net_rebuild_header,
.cache = isdn_header_cache,
.cache_update = isdn_header_cache_update,
};
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 84b35925ee4d..8dc7290089bb 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -112,8 +112,8 @@ mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
}
static int
-mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len, int flags)
+mISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+ int flags)
{
struct sk_buff *skb;
struct sock *sk = sock->sk;
@@ -173,8 +173,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
}
static int
-mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len)
+mISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
struct sk_buff *skb;