Loading drivers/bluetooth/bluecard_cs.c +1 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ #include <linux/wait.h> #include <linux/skbuff.h> #include <asm/io.h> #include <linux/io.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> Loading drivers/bluetooth/hci_bcsp.c +1 −1 Original line number Diff line number Diff line Loading @@ -244,7 +244,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, if (rel) { hdr[0] |= 0x80 + bcsp->msgq_txseq; BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; bcsp->msgq_txseq = (bcsp->msgq_txseq + 1) & 0x07; } if (bcsp->use_crc) Loading drivers/isdn/gigaset/asyncdata.c +11 −33 Original line number Diff line number Diff line Loading @@ -126,26 +126,6 @@ static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf) return numbytes; } /* set up next receive skb for data mode */ static void new_rcv_skb(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; unsigned short hw_hdr_len = cs->hw_hdr_len; if (bcs->ignore) { bcs->skb = NULL; return; } bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len); if (bcs->skb == NULL) { dev_warn(cs->dev, "could not allocate new skb\n"); return; } skb_reserve(bcs->skb, hw_hdr_len); } /* process a block of received bytes in HDLC data mode * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC) * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. Loading @@ -159,8 +139,8 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; __u16 fcs = bcs->fcs; struct sk_buff *skb = bcs->skb; __u16 fcs = bcs->rx_fcs; struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; Loading Loading @@ -245,8 +225,7 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) /* prepare reception of next frame */ inputstate &= ~INS_have_data; new_rcv_skb(bcs); skb = bcs->skb; skb = gigaset_new_rx_skb(bcs); } else { /* empty frame (7E 7E) */ #ifdef CONFIG_GIGASET_DEBUG Loading @@ -255,8 +234,7 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) if (!skb) { /* skipped (?) */ gigaset_isdn_rcv_err(bcs); new_rcv_skb(bcs); skb = bcs->skb; skb = gigaset_new_rx_skb(bcs); } } Loading @@ -279,11 +257,11 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) #endif inputstate |= INS_have_data; if (skb) { if (skb->len == SBUFSIZE) { if (skb->len >= bcs->rx_bufsize) { dev_warn(cs->dev, "received packet too long\n"); dev_kfree_skb_any(skb); /* skip remainder of packet */ bcs->skb = skb = NULL; bcs->rx_skb = skb = NULL; } else { *__skb_put(skb, 1) = c; fcs = crc_ccitt_byte(fcs, c); Loading @@ -292,7 +270,7 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) } bcs->inputstate = inputstate; bcs->fcs = fcs; bcs->rx_fcs = fcs; return procbytes; } Loading @@ -308,18 +286,18 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; struct sk_buff *skb = bcs->skb; struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; if (!skb) { /* skip this block */ new_rcv_skb(bcs); gigaset_new_rx_skb(bcs); return numbytes; } while (procbytes < numbytes && skb->len < SBUFSIZE) { while (procbytes < numbytes && skb->len < bcs->rx_bufsize) { c = *src++; procbytes++; Loading @@ -343,7 +321,7 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) if (inputstate & INS_have_data) { gigaset_skb_rcvd(bcs, skb); inputstate &= ~INS_have_data; new_rcv_skb(bcs); gigaset_new_rx_skb(bcs); } bcs->inputstate = inputstate; Loading drivers/isdn/gigaset/capi.c +285 −120 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ #define MAX_NUMBER_DIGITS 20 #define MAX_FMT_IE_LEN 20 /* values for gigaset_capi_appl.connected */ /* values for bcs->apconnstate */ #define APCONN_NONE 0 /* inactive/listening */ #define APCONN_SETUP 1 /* connecting */ #define APCONN_ACTIVE 2 /* B channel up */ Loading @@ -80,10 +80,10 @@ struct gigaset_capi_appl { struct list_head ctrlist; struct gigaset_capi_appl *bcnext; u16 id; struct capi_register_params rp; u16 nextMessageNumber; u32 listenInfoMask; u32 listenCIPmask; int connected; }; /* CAPI specific controller data structure */ Loading Loading @@ -319,6 +319,39 @@ static const char *format_ie(const char *ie) return result; } /* * emit DATA_B3_CONF message */ static void send_data_b3_conf(struct cardstate *cs, struct capi_ctr *ctr, u16 appl, u16 msgid, int channel, u16 handle, u16 info) { struct sk_buff *cskb; u8 *msg; cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); if (!cskb) { dev_err(cs->dev, "%s: out of memory\n", __func__); return; } /* frequent message, avoid _cmsg overhead */ msg = __skb_put(cskb, CAPI_DATA_B3_CONF_LEN); CAPIMSG_SETLEN(msg, CAPI_DATA_B3_CONF_LEN); CAPIMSG_SETAPPID(msg, appl); CAPIMSG_SETCOMMAND(msg, CAPI_DATA_B3); CAPIMSG_SETSUBCOMMAND(msg, CAPI_CONF); CAPIMSG_SETMSGID(msg, msgid); CAPIMSG_SETCONTROLLER(msg, ctr->cnr); CAPIMSG_SETPLCI_PART(msg, channel); CAPIMSG_SETNCCI_PART(msg, 1); CAPIMSG_SETHANDLE_CONF(msg, handle); CAPIMSG_SETINFO_CONF(msg, info); /* emit message */ dump_rawmsg(DEBUG_MCMD, __func__, msg); capi_ctr_handle_message(ctr, appl, cskb); } /* * driver interface functions Loading @@ -339,7 +372,6 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; unsigned char *req = skb_mac_header(dskb); struct sk_buff *cskb; u16 flags; /* update statistics */ Loading @@ -351,39 +383,22 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) } /* don't send further B3 messages if disconnected */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); return; } /* ToDo: honor unset "delivery confirmation" bit */ /* * send DATA_B3_CONF if "delivery confirmation" bit was set in request; * otherwise it has already been sent by do_data_b3_req() */ flags = CAPIMSG_FLAGS(req); /* build DATA_B3_CONF message */ cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); if (!cskb) { dev_err(cs->dev, "%s: out of memory\n", __func__); return; } /* frequent message, avoid _cmsg overhead */ CAPIMSG_SETLEN(cskb->data, CAPI_DATA_B3_CONF_LEN); CAPIMSG_SETAPPID(cskb->data, ap->id); CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3); CAPIMSG_SETSUBCOMMAND(cskb->data, CAPI_CONF); CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(req)); CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr); CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1); CAPIMSG_SETNCCI_PART(cskb->data, 1); CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(req)); if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) CAPIMSG_SETINFO_CONF(cskb->data, CapiFlagsNotSupportedByProtocol); else CAPIMSG_SETINFO_CONF(cskb->data, CAPI_NOERROR); /* emit message */ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_CONF", cskb->data); capi_ctr_handle_message(&iif->ctr, ap->id, cskb); if (flags & CAPI_FLAGS_DELIVERY_CONFIRMATION) send_data_b3_conf(cs, &iif->ctr, ap->id, CAPIMSG_MSGID(req), bcs->channel + 1, CAPIMSG_HANDLE_REQ(req), (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) ? CapiFlagsNotSupportedByProtocol : CAPI_NOERROR); } EXPORT_SYMBOL_GPL(gigaset_skb_sent); Loading Loading @@ -412,7 +427,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) } /* don't send further B3 messages if disconnected */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); dev_kfree_skb_any(skb); return; Loading Loading @@ -484,6 +499,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state) u32 actCIPmask; struct sk_buff *skb; unsigned int msgsize; unsigned long flags; int i; /* Loading Loading @@ -608,7 +624,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state) format_ie(iif->hcmsg.CalledPartyNumber)); /* scan application list for matching listeners */ spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", __func__, bcs->ap, bcs->apconnstate); bcs->ap = NULL; bcs->apconnstate = APCONN_NONE; } spin_unlock_irqrestore(&bcs->aplock, flags); actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); list_for_each_entry(ap, &iif->appls, ctrlist) if (actCIPmask & ap->listenCIPmask) { Loading @@ -626,10 +649,12 @@ int gigaset_isdn_icall(struct at_state_t *at_state) dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); /* add to listeners on this B channel, update state */ spin_lock_irqsave(&bcs->aplock, flags); ap->bcnext = bcs->ap; bcs->ap = ap; bcs->chstate |= CHS_NOTIFY_LL; ap->connected = APCONN_SETUP; bcs->apconnstate = APCONN_SETUP; spin_unlock_irqrestore(&bcs->aplock, flags); /* emit message */ capi_ctr_handle_message(&iif->ctr, ap->id, skb); Loading @@ -654,7 +679,7 @@ static void send_disconnect_ind(struct bc_state *bcs, struct gigaset_capi_ctr *iif = cs->iif; struct sk_buff *skb; if (ap->connected == APCONN_NONE) if (bcs->apconnstate == APCONN_NONE) return; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, Loading @@ -668,7 +693,6 @@ static void send_disconnect_ind(struct bc_state *bcs, } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); ap->connected = APCONN_NONE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } Loading @@ -685,9 +709,9 @@ static void send_disconnect_b3_ind(struct bc_state *bcs, struct sk_buff *skb; /* nothing to do if no logical connection active */ if (ap->connected < APCONN_ACTIVE) if (bcs->apconnstate < APCONN_ACTIVE) return; ap->connected = APCONN_SETUP; bcs->apconnstate = APCONN_SETUP; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, ap->nextMessageNumber++, Loading @@ -714,14 +738,25 @@ void gigaset_isdn_connD(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; struct gigaset_capi_appl *ap; struct sk_buff *skb; unsigned int msgsize; unsigned long flags; spin_lock_irqsave(&bcs->aplock, flags); ap = bcs->ap; if (!ap) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } if (bcs->apconnstate == APCONN_NONE) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; } spin_unlock_irqrestore(&bcs->aplock, flags); while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", Loading @@ -730,11 +765,6 @@ void gigaset_isdn_connD(struct bc_state *bcs) CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } if (ap->connected == APCONN_NONE) { dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; } /* prepare CONNECT_ACTIVE_IND message * Note: LLC not supported by device Loading Loading @@ -772,17 +802,24 @@ void gigaset_isdn_connD(struct bc_state *bcs) void gigaset_isdn_hupD(struct bc_state *bcs) { struct gigaset_capi_appl *ap; unsigned long flags; /* * ToDo: pass on reason code reported by device * (requires ev-layer state machine extension to collect * ZCAU device reply) */ for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { spin_lock_irqsave(&bcs->aplock, flags); while (bcs->ap != NULL) { ap = bcs->ap; bcs->ap = ap->bcnext; spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_b3_ind(bcs, ap); send_disconnect_ind(bcs, ap, 0); spin_lock_irqsave(&bcs->aplock, flags); } bcs->ap = NULL; bcs->apconnstate = APCONN_NONE; spin_unlock_irqrestore(&bcs->aplock, flags); } /** Loading @@ -796,24 +833,21 @@ void gigaset_isdn_connB(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; struct gigaset_capi_appl *ap; struct sk_buff *skb; unsigned long flags; unsigned int msgsize; u8 command; spin_lock_irqsave(&bcs->aplock, flags); ap = bcs->ap; if (!ap) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", __func__, ap->bcnext->id); send_disconnect_ind(bcs, ap->bcnext, CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } if (!ap->connected) { if (!bcs->apconnstate) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; Loading @@ -825,13 +859,26 @@ void gigaset_isdn_connB(struct bc_state *bcs) * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP * Parameters in both cases always: NCCI = 1, NCPI empty */ if (ap->connected >= APCONN_ACTIVE) { if (bcs->apconnstate >= APCONN_ACTIVE) { command = CAPI_CONNECT_B3_ACTIVE; msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; } else { command = CAPI_CONNECT_B3; msgsize = CAPI_CONNECT_B3_IND_BASELEN; } bcs->apconnstate = APCONN_ACTIVE; spin_unlock_irqrestore(&bcs->aplock, flags); while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", __func__, ap->bcnext->id); send_disconnect_ind(bcs, ap->bcnext, CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, ap->nextMessageNumber++, iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); Loading @@ -842,7 +889,6 @@ void gigaset_isdn_connB(struct bc_state *bcs) } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); ap->connected = APCONN_ACTIVE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } Loading Loading @@ -945,8 +991,64 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, return; } ap->id = appl; ap->rp = *rp; list_add(&ap->ctrlist, &iif->appls); dev_info(cs->dev, "application %u registered\n", ap->id); } /* * remove CAPI application from channel * helper function to keep indentation levels down and stay in 80 columns */ static inline void remove_appl_from_channel(struct bc_state *bcs, struct gigaset_capi_appl *ap) { struct cardstate *cs = bcs->cs; struct gigaset_capi_appl *bcap; unsigned long flags; int prevconnstate; spin_lock_irqsave(&bcs->aplock, flags); bcap = bcs->ap; if (bcap == NULL) { spin_unlock_irqrestore(&bcs->aplock, flags); return; } /* check first application on channel */ if (bcap == ap) { bcs->ap = ap->bcnext; if (bcs->ap != NULL) { spin_unlock_irqrestore(&bcs->aplock, flags); return; } /* none left, clear channel state */ prevconnstate = bcs->apconnstate; bcs->apconnstate = APCONN_NONE; spin_unlock_irqrestore(&bcs->aplock, flags); if (prevconnstate == APCONN_ACTIVE) { dev_notice(cs->dev, "%s: hanging up channel %u\n", __func__, bcs->channel); gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL); gigaset_schedule_event(cs); } return; } /* check remaining list */ do { if (bcap->bcnext == ap) { bcap->bcnext = bcap->bcnext->bcnext; return; } bcap = bcap->bcnext; } while (bcap != NULL); spin_unlock_irqrestore(&bcs->aplock, flags); } /* Loading @@ -958,19 +1060,19 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl) = container_of(ctr, struct gigaset_capi_ctr, ctr); struct cardstate *cs = iif->ctr.driverdata; struct gigaset_capi_appl *ap, *tmp; unsigned ch; list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) if (ap->id == appl) { if (ap->connected != APCONN_NONE) { dev_err(cs->dev, "%s: application %u still connected\n", __func__, ap->id); /* ToDo: clear active connection */ } /* remove from any channels */ for (ch = 0; ch < cs->channels; ch++) remove_appl_from_channel(&cs->bcs[ch], ap); /* remove from registration list */ list_del(&ap->ctrlist); kfree(ap); dev_info(cs->dev, "application %u released\n", appl); } } /* Loading Loading @@ -1149,7 +1251,8 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, char **commands; char *s; u8 *pp; int i, l; unsigned long flags; int i, l, lbc, lhlc; u16 info; /* decode message */ Loading @@ -1164,8 +1267,18 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiNoPlciAvailable); return; } spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", __func__, bcs->ap, bcs->apconnstate); ap->bcnext = NULL; bcs->ap = ap; bcs->apconnstate = APCONN_SETUP; spin_unlock_irqrestore(&bcs->aplock, flags); bcs->rx_bufsize = ap->rp.datablklen; dev_kfree_skb(bcs->rx_skb); gigaset_new_rx_skb(bcs); cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8; /* build command table */ Loading Loading @@ -1273,43 +1386,60 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } /* check/encode parameter: BC */ if (cmsg->BC && cmsg->BC[0]) { /* explicit BC overrides CIP */ l = 2*cmsg->BC[0] + 7; /* * check/encode parameters: BC & HLC * must be encoded together as device doesn't accept HLC separately * explicit parameters override values derived from CIP */ /* determine lengths */ if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ lbc = 2*cmsg->BC[0]; else if (cip2bchlc[cmsg->CIPValue].bc) /* BC derived from CIP */ lbc = strlen(cip2bchlc[cmsg->CIPValue].bc); else /* no BC */ lbc = 0; if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ lhlc = 2*cmsg->HLC[0]; else if (cip2bchlc[cmsg->CIPValue].hlc) /* HLC derived from CIP */ lhlc = strlen(cip2bchlc[cmsg->CIPValue].hlc); else /* no HLC */ lhlc = 0; if (lbc) { /* have BC: allocate and assemble command string */ l = lbc + 7; /* "^SBC=" + value + "\r" + null byte */ if (lhlc) l += lhlc + 7; /* ";^SHLC=" + value */ commands[AT_BC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_BC]) goto oom; strcpy(commands[AT_BC], "^SBC="); if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ decode_ie(cmsg->BC, commands[AT_BC] + 5); strcpy(commands[AT_BC] + l - 2, "\r"); } else if (cip2bchlc[cmsg->CIPValue].bc) { l = strlen(cip2bchlc[cmsg->CIPValue].bc) + 7; commands[AT_BC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_BC]) goto oom; snprintf(commands[AT_BC], l, "^SBC=%s\r", else /* BC derived from CIP */ strcpy(commands[AT_BC] + 5, cip2bchlc[cmsg->CIPValue].bc); } /* check/encode parameter: HLC */ if (cmsg->HLC && cmsg->HLC[0]) { /* explicit HLC overrides CIP */ l = 2*cmsg->HLC[0] + 7; commands[AT_HLC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_HLC]) goto oom; strcpy(commands[AT_HLC], "^SHLC="); decode_ie(cmsg->HLC, commands[AT_HLC]+5); strcpy(commands[AT_HLC] + l - 2, "\r"); } else if (cip2bchlc[cmsg->CIPValue].hlc) { l = strlen(cip2bchlc[cmsg->CIPValue].hlc) + 7; commands[AT_HLC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_HLC]) goto oom; snprintf(commands[AT_HLC], l, "^SHLC=%s\r", if (lhlc) { strcpy(commands[AT_BC] + lbc + 5, ";^SHLC="); if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ decode_ie(cmsg->HLC, commands[AT_BC] + lbc + 12); else /* HLC derived from CIP */ strcpy(commands[AT_BC] + lbc + 12, cip2bchlc[cmsg->CIPValue].hlc); } strcpy(commands[AT_BC] + l - 2, "\r"); } else { /* no BC */ if (lhlc) { dev_notice(cs->dev, "%s: cannot set HLC without BC\n", "CONNECT_REQ"); info = CapiIllMessageParmCoding; /* ? */ goto error; } } /* check/encode parameter: B Protocol */ if (cmsg->BProtocol == CAPI_DEFAULT) { Loading @@ -1322,13 +1452,13 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, Loading Loading @@ -1382,7 +1512,6 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } gigaset_schedule_event(cs); ap->connected = APCONN_SETUP; send_conf(iif, ap, skb, CapiSuccess); return; Loading Loading @@ -1410,6 +1539,7 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; struct gigaset_capi_appl *oap; unsigned long flags; int channel; /* decode message */ Loading @@ -1429,12 +1559,24 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, switch (cmsg->Reject) { case 0: /* Accept */ /* drop all competing applications, keep only this one */ for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) if (oap != ap) spin_lock_irqsave(&bcs->aplock, flags); while (bcs->ap != NULL) { oap = bcs->ap; bcs->ap = oap->bcnext; if (oap != ap) { spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); spin_lock_irqsave(&bcs->aplock, flags); } } ap->bcnext = NULL; bcs->ap = ap; spin_unlock_irqrestore(&bcs->aplock, flags); bcs->rx_bufsize = ap->rp.datablklen; dev_kfree_skb(bcs->rx_skb); gigaset_new_rx_skb(bcs); bcs->chstate |= CHS_NOTIFY_LL; /* check/encode B channel protocol */ Loading @@ -1448,13 +1590,13 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, Loading Loading @@ -1502,31 +1644,45 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, send_disconnect_ind(bcs, ap, 0); /* remove it from the list of listening apps */ spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap == ap) { bcs->ap = ap->bcnext; if (bcs->ap == NULL) if (bcs->ap == NULL) { /* last one: stop ev-layer hupD notifications */ bcs->apconnstate = APCONN_NONE; bcs->chstate &= ~CHS_NOTIFY_LL; } spin_unlock_irqrestore(&bcs->aplock, flags); return; } for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { if (oap->bcnext == ap) { oap->bcnext = oap->bcnext->bcnext; spin_unlock_irqrestore(&bcs->aplock, flags); return; } } spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: application %u not found\n", __func__, ap->id); return; default: /* Reject */ /* drop all competing applications, keep only this one */ for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) if (oap != ap) spin_lock_irqsave(&bcs->aplock, flags); while (bcs->ap != NULL) { oap = bcs->ap; bcs->ap = oap->bcnext; if (oap != ap) { spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); spin_lock_irqsave(&bcs->aplock, flags); } } ap->bcnext = NULL; bcs->ap = ap; spin_unlock_irqrestore(&bcs->aplock, flags); /* reject call - will trigger DISCONNECT_IND for this app */ dev_info(cs->dev, "%s: Reject=%x\n", Loading @@ -1549,6 +1705,7 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; int channel; /* decode message */ Loading @@ -1563,9 +1720,10 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } bcs = &cs->bcs[channel-1]; /* mark logical connection active */ ap->connected = APCONN_ACTIVE; bcs->apconnstate = APCONN_ACTIVE; /* build NCCI: always 1 (one B3 connection only) */ cmsg->adr.adrNCCI |= 1 << 16; Loading Loading @@ -1611,7 +1769,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif, if (cmsg->Reject) { /* Reject: clear B3 connect received flag */ ap->connected = APCONN_SETUP; bcs->apconnstate = APCONN_SETUP; /* trigger hangup, causing eventual DISCONNECT_IND */ if (!gigaset_add_event(cs, &bcs->at_state, Loading Loading @@ -1683,11 +1841,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, } /* skip if DISCONNECT_IND already sent */ if (!ap->connected) if (!bcs->apconnstate) return; /* check for active logical connection */ if (ap->connected >= APCONN_ACTIVE) { if (bcs->apconnstate >= APCONN_ACTIVE) { /* * emit DISCONNECT_B3_IND with cause 0x3301 * use separate cmsg structure, as the content of iif->acmsg Loading Loading @@ -1736,6 +1894,7 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; int channel; /* decode message */ Loading @@ -1751,17 +1910,17 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } bcs = &cs->bcs[channel-1]; /* reject if logical connection not active */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } /* trigger hangup, causing eventual DISCONNECT_B3_IND */ if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, EV_HUP, NULL, 0, NULL)) { if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } Loading @@ -1782,11 +1941,14 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, struct sk_buff *skb) { struct cardstate *cs = iif->ctr.driverdata; struct bc_state *bcs; int channel = CAPIMSG_PLCI_PART(skb->data); u16 ncci = CAPIMSG_NCCI_PART(skb->data); u16 msglen = CAPIMSG_LEN(skb->data); u16 datalen = CAPIMSG_DATALEN(skb->data); u16 flags = CAPIMSG_FLAGS(skb->data); u16 msgid = CAPIMSG_MSGID(skb->data); u16 handle = CAPIMSG_HANDLE_REQ(skb->data); /* frequent message, avoid _cmsg overhead */ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data); Loading @@ -1802,6 +1964,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } bcs = &cs->bcs[channel-1]; if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) dev_notice(cs->dev, "%s: unexpected length %d\n", "DATA_B3_REQ", msglen); Loading @@ -1821,7 +1984,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, } /* reject if logical connection not active */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } Loading @@ -1832,17 +1995,19 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, skb_pull(skb, msglen); /* pass to device-specific module */ if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { if (cs->ops->send_skb(bcs, skb) < 0) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } /* DATA_B3_CONF reply will be sent by gigaset_skb_sent() */ /* * ToDo: honor unset "delivery confirmation" bit * (send DATA_B3_CONF immediately?) * DATA_B3_CONF will be sent by gigaset_skb_sent() only if "delivery * confirmation" bit is set; otherwise we have to send it now */ if (!(flags & CAPI_FLAGS_DELIVERY_CONFIRMATION)) send_data_b3_conf(cs, &iif->ctr, ap->id, msgid, channel, handle, flags ? CapiFlagsNotSupportedByProtocol : CAPI_NOERROR); } /* Loading Loading
drivers/bluetooth/bluecard_cs.c +1 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ #include <linux/wait.h> #include <linux/skbuff.h> #include <asm/io.h> #include <linux/io.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> Loading
drivers/bluetooth/hci_bcsp.c +1 −1 Original line number Diff line number Diff line Loading @@ -244,7 +244,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, if (rel) { hdr[0] |= 0x80 + bcsp->msgq_txseq; BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; bcsp->msgq_txseq = (bcsp->msgq_txseq + 1) & 0x07; } if (bcsp->use_crc) Loading
drivers/isdn/gigaset/asyncdata.c +11 −33 Original line number Diff line number Diff line Loading @@ -126,26 +126,6 @@ static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf) return numbytes; } /* set up next receive skb for data mode */ static void new_rcv_skb(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; unsigned short hw_hdr_len = cs->hw_hdr_len; if (bcs->ignore) { bcs->skb = NULL; return; } bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len); if (bcs->skb == NULL) { dev_warn(cs->dev, "could not allocate new skb\n"); return; } skb_reserve(bcs->skb, hw_hdr_len); } /* process a block of received bytes in HDLC data mode * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC) * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. Loading @@ -159,8 +139,8 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; __u16 fcs = bcs->fcs; struct sk_buff *skb = bcs->skb; __u16 fcs = bcs->rx_fcs; struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; Loading Loading @@ -245,8 +225,7 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) /* prepare reception of next frame */ inputstate &= ~INS_have_data; new_rcv_skb(bcs); skb = bcs->skb; skb = gigaset_new_rx_skb(bcs); } else { /* empty frame (7E 7E) */ #ifdef CONFIG_GIGASET_DEBUG Loading @@ -255,8 +234,7 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) if (!skb) { /* skipped (?) */ gigaset_isdn_rcv_err(bcs); new_rcv_skb(bcs); skb = bcs->skb; skb = gigaset_new_rx_skb(bcs); } } Loading @@ -279,11 +257,11 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) #endif inputstate |= INS_have_data; if (skb) { if (skb->len == SBUFSIZE) { if (skb->len >= bcs->rx_bufsize) { dev_warn(cs->dev, "received packet too long\n"); dev_kfree_skb_any(skb); /* skip remainder of packet */ bcs->skb = skb = NULL; bcs->rx_skb = skb = NULL; } else { *__skb_put(skb, 1) = c; fcs = crc_ccitt_byte(fcs, c); Loading @@ -292,7 +270,7 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) } bcs->inputstate = inputstate; bcs->fcs = fcs; bcs->rx_fcs = fcs; return procbytes; } Loading @@ -308,18 +286,18 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; struct sk_buff *skb = bcs->skb; struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; if (!skb) { /* skip this block */ new_rcv_skb(bcs); gigaset_new_rx_skb(bcs); return numbytes; } while (procbytes < numbytes && skb->len < SBUFSIZE) { while (procbytes < numbytes && skb->len < bcs->rx_bufsize) { c = *src++; procbytes++; Loading @@ -343,7 +321,7 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) if (inputstate & INS_have_data) { gigaset_skb_rcvd(bcs, skb); inputstate &= ~INS_have_data; new_rcv_skb(bcs); gigaset_new_rx_skb(bcs); } bcs->inputstate = inputstate; Loading
drivers/isdn/gigaset/capi.c +285 −120 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ #define MAX_NUMBER_DIGITS 20 #define MAX_FMT_IE_LEN 20 /* values for gigaset_capi_appl.connected */ /* values for bcs->apconnstate */ #define APCONN_NONE 0 /* inactive/listening */ #define APCONN_SETUP 1 /* connecting */ #define APCONN_ACTIVE 2 /* B channel up */ Loading @@ -80,10 +80,10 @@ struct gigaset_capi_appl { struct list_head ctrlist; struct gigaset_capi_appl *bcnext; u16 id; struct capi_register_params rp; u16 nextMessageNumber; u32 listenInfoMask; u32 listenCIPmask; int connected; }; /* CAPI specific controller data structure */ Loading Loading @@ -319,6 +319,39 @@ static const char *format_ie(const char *ie) return result; } /* * emit DATA_B3_CONF message */ static void send_data_b3_conf(struct cardstate *cs, struct capi_ctr *ctr, u16 appl, u16 msgid, int channel, u16 handle, u16 info) { struct sk_buff *cskb; u8 *msg; cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); if (!cskb) { dev_err(cs->dev, "%s: out of memory\n", __func__); return; } /* frequent message, avoid _cmsg overhead */ msg = __skb_put(cskb, CAPI_DATA_B3_CONF_LEN); CAPIMSG_SETLEN(msg, CAPI_DATA_B3_CONF_LEN); CAPIMSG_SETAPPID(msg, appl); CAPIMSG_SETCOMMAND(msg, CAPI_DATA_B3); CAPIMSG_SETSUBCOMMAND(msg, CAPI_CONF); CAPIMSG_SETMSGID(msg, msgid); CAPIMSG_SETCONTROLLER(msg, ctr->cnr); CAPIMSG_SETPLCI_PART(msg, channel); CAPIMSG_SETNCCI_PART(msg, 1); CAPIMSG_SETHANDLE_CONF(msg, handle); CAPIMSG_SETINFO_CONF(msg, info); /* emit message */ dump_rawmsg(DEBUG_MCMD, __func__, msg); capi_ctr_handle_message(ctr, appl, cskb); } /* * driver interface functions Loading @@ -339,7 +372,6 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; unsigned char *req = skb_mac_header(dskb); struct sk_buff *cskb; u16 flags; /* update statistics */ Loading @@ -351,39 +383,22 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) } /* don't send further B3 messages if disconnected */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); return; } /* ToDo: honor unset "delivery confirmation" bit */ /* * send DATA_B3_CONF if "delivery confirmation" bit was set in request; * otherwise it has already been sent by do_data_b3_req() */ flags = CAPIMSG_FLAGS(req); /* build DATA_B3_CONF message */ cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); if (!cskb) { dev_err(cs->dev, "%s: out of memory\n", __func__); return; } /* frequent message, avoid _cmsg overhead */ CAPIMSG_SETLEN(cskb->data, CAPI_DATA_B3_CONF_LEN); CAPIMSG_SETAPPID(cskb->data, ap->id); CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3); CAPIMSG_SETSUBCOMMAND(cskb->data, CAPI_CONF); CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(req)); CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr); CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1); CAPIMSG_SETNCCI_PART(cskb->data, 1); CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(req)); if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) CAPIMSG_SETINFO_CONF(cskb->data, CapiFlagsNotSupportedByProtocol); else CAPIMSG_SETINFO_CONF(cskb->data, CAPI_NOERROR); /* emit message */ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_CONF", cskb->data); capi_ctr_handle_message(&iif->ctr, ap->id, cskb); if (flags & CAPI_FLAGS_DELIVERY_CONFIRMATION) send_data_b3_conf(cs, &iif->ctr, ap->id, CAPIMSG_MSGID(req), bcs->channel + 1, CAPIMSG_HANDLE_REQ(req), (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) ? CapiFlagsNotSupportedByProtocol : CAPI_NOERROR); } EXPORT_SYMBOL_GPL(gigaset_skb_sent); Loading Loading @@ -412,7 +427,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) } /* don't send further B3 messages if disconnected */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); dev_kfree_skb_any(skb); return; Loading Loading @@ -484,6 +499,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state) u32 actCIPmask; struct sk_buff *skb; unsigned int msgsize; unsigned long flags; int i; /* Loading Loading @@ -608,7 +624,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state) format_ie(iif->hcmsg.CalledPartyNumber)); /* scan application list for matching listeners */ spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", __func__, bcs->ap, bcs->apconnstate); bcs->ap = NULL; bcs->apconnstate = APCONN_NONE; } spin_unlock_irqrestore(&bcs->aplock, flags); actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); list_for_each_entry(ap, &iif->appls, ctrlist) if (actCIPmask & ap->listenCIPmask) { Loading @@ -626,10 +649,12 @@ int gigaset_isdn_icall(struct at_state_t *at_state) dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); /* add to listeners on this B channel, update state */ spin_lock_irqsave(&bcs->aplock, flags); ap->bcnext = bcs->ap; bcs->ap = ap; bcs->chstate |= CHS_NOTIFY_LL; ap->connected = APCONN_SETUP; bcs->apconnstate = APCONN_SETUP; spin_unlock_irqrestore(&bcs->aplock, flags); /* emit message */ capi_ctr_handle_message(&iif->ctr, ap->id, skb); Loading @@ -654,7 +679,7 @@ static void send_disconnect_ind(struct bc_state *bcs, struct gigaset_capi_ctr *iif = cs->iif; struct sk_buff *skb; if (ap->connected == APCONN_NONE) if (bcs->apconnstate == APCONN_NONE) return; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, Loading @@ -668,7 +693,6 @@ static void send_disconnect_ind(struct bc_state *bcs, } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); ap->connected = APCONN_NONE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } Loading @@ -685,9 +709,9 @@ static void send_disconnect_b3_ind(struct bc_state *bcs, struct sk_buff *skb; /* nothing to do if no logical connection active */ if (ap->connected < APCONN_ACTIVE) if (bcs->apconnstate < APCONN_ACTIVE) return; ap->connected = APCONN_SETUP; bcs->apconnstate = APCONN_SETUP; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, ap->nextMessageNumber++, Loading @@ -714,14 +738,25 @@ void gigaset_isdn_connD(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; struct gigaset_capi_appl *ap; struct sk_buff *skb; unsigned int msgsize; unsigned long flags; spin_lock_irqsave(&bcs->aplock, flags); ap = bcs->ap; if (!ap) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } if (bcs->apconnstate == APCONN_NONE) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; } spin_unlock_irqrestore(&bcs->aplock, flags); while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", Loading @@ -730,11 +765,6 @@ void gigaset_isdn_connD(struct bc_state *bcs) CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } if (ap->connected == APCONN_NONE) { dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; } /* prepare CONNECT_ACTIVE_IND message * Note: LLC not supported by device Loading Loading @@ -772,17 +802,24 @@ void gigaset_isdn_connD(struct bc_state *bcs) void gigaset_isdn_hupD(struct bc_state *bcs) { struct gigaset_capi_appl *ap; unsigned long flags; /* * ToDo: pass on reason code reported by device * (requires ev-layer state machine extension to collect * ZCAU device reply) */ for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { spin_lock_irqsave(&bcs->aplock, flags); while (bcs->ap != NULL) { ap = bcs->ap; bcs->ap = ap->bcnext; spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_b3_ind(bcs, ap); send_disconnect_ind(bcs, ap, 0); spin_lock_irqsave(&bcs->aplock, flags); } bcs->ap = NULL; bcs->apconnstate = APCONN_NONE; spin_unlock_irqrestore(&bcs->aplock, flags); } /** Loading @@ -796,24 +833,21 @@ void gigaset_isdn_connB(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; struct gigaset_capi_appl *ap; struct sk_buff *skb; unsigned long flags; unsigned int msgsize; u8 command; spin_lock_irqsave(&bcs->aplock, flags); ap = bcs->ap; if (!ap) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", __func__, ap->bcnext->id); send_disconnect_ind(bcs, ap->bcnext, CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } if (!ap->connected) { if (!bcs->apconnstate) { spin_unlock_irqrestore(&bcs->aplock, flags); dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; Loading @@ -825,13 +859,26 @@ void gigaset_isdn_connB(struct bc_state *bcs) * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP * Parameters in both cases always: NCCI = 1, NCPI empty */ if (ap->connected >= APCONN_ACTIVE) { if (bcs->apconnstate >= APCONN_ACTIVE) { command = CAPI_CONNECT_B3_ACTIVE; msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; } else { command = CAPI_CONNECT_B3; msgsize = CAPI_CONNECT_B3_IND_BASELEN; } bcs->apconnstate = APCONN_ACTIVE; spin_unlock_irqrestore(&bcs->aplock, flags); while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", __func__, ap->bcnext->id); send_disconnect_ind(bcs, ap->bcnext, CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, ap->nextMessageNumber++, iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); Loading @@ -842,7 +889,6 @@ void gigaset_isdn_connB(struct bc_state *bcs) } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); ap->connected = APCONN_ACTIVE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } Loading Loading @@ -945,8 +991,64 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, return; } ap->id = appl; ap->rp = *rp; list_add(&ap->ctrlist, &iif->appls); dev_info(cs->dev, "application %u registered\n", ap->id); } /* * remove CAPI application from channel * helper function to keep indentation levels down and stay in 80 columns */ static inline void remove_appl_from_channel(struct bc_state *bcs, struct gigaset_capi_appl *ap) { struct cardstate *cs = bcs->cs; struct gigaset_capi_appl *bcap; unsigned long flags; int prevconnstate; spin_lock_irqsave(&bcs->aplock, flags); bcap = bcs->ap; if (bcap == NULL) { spin_unlock_irqrestore(&bcs->aplock, flags); return; } /* check first application on channel */ if (bcap == ap) { bcs->ap = ap->bcnext; if (bcs->ap != NULL) { spin_unlock_irqrestore(&bcs->aplock, flags); return; } /* none left, clear channel state */ prevconnstate = bcs->apconnstate; bcs->apconnstate = APCONN_NONE; spin_unlock_irqrestore(&bcs->aplock, flags); if (prevconnstate == APCONN_ACTIVE) { dev_notice(cs->dev, "%s: hanging up channel %u\n", __func__, bcs->channel); gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL); gigaset_schedule_event(cs); } return; } /* check remaining list */ do { if (bcap->bcnext == ap) { bcap->bcnext = bcap->bcnext->bcnext; return; } bcap = bcap->bcnext; } while (bcap != NULL); spin_unlock_irqrestore(&bcs->aplock, flags); } /* Loading @@ -958,19 +1060,19 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl) = container_of(ctr, struct gigaset_capi_ctr, ctr); struct cardstate *cs = iif->ctr.driverdata; struct gigaset_capi_appl *ap, *tmp; unsigned ch; list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) if (ap->id == appl) { if (ap->connected != APCONN_NONE) { dev_err(cs->dev, "%s: application %u still connected\n", __func__, ap->id); /* ToDo: clear active connection */ } /* remove from any channels */ for (ch = 0; ch < cs->channels; ch++) remove_appl_from_channel(&cs->bcs[ch], ap); /* remove from registration list */ list_del(&ap->ctrlist); kfree(ap); dev_info(cs->dev, "application %u released\n", appl); } } /* Loading Loading @@ -1149,7 +1251,8 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, char **commands; char *s; u8 *pp; int i, l; unsigned long flags; int i, l, lbc, lhlc; u16 info; /* decode message */ Loading @@ -1164,8 +1267,18 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiNoPlciAvailable); return; } spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", __func__, bcs->ap, bcs->apconnstate); ap->bcnext = NULL; bcs->ap = ap; bcs->apconnstate = APCONN_SETUP; spin_unlock_irqrestore(&bcs->aplock, flags); bcs->rx_bufsize = ap->rp.datablklen; dev_kfree_skb(bcs->rx_skb); gigaset_new_rx_skb(bcs); cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8; /* build command table */ Loading Loading @@ -1273,43 +1386,60 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } /* check/encode parameter: BC */ if (cmsg->BC && cmsg->BC[0]) { /* explicit BC overrides CIP */ l = 2*cmsg->BC[0] + 7; /* * check/encode parameters: BC & HLC * must be encoded together as device doesn't accept HLC separately * explicit parameters override values derived from CIP */ /* determine lengths */ if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ lbc = 2*cmsg->BC[0]; else if (cip2bchlc[cmsg->CIPValue].bc) /* BC derived from CIP */ lbc = strlen(cip2bchlc[cmsg->CIPValue].bc); else /* no BC */ lbc = 0; if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ lhlc = 2*cmsg->HLC[0]; else if (cip2bchlc[cmsg->CIPValue].hlc) /* HLC derived from CIP */ lhlc = strlen(cip2bchlc[cmsg->CIPValue].hlc); else /* no HLC */ lhlc = 0; if (lbc) { /* have BC: allocate and assemble command string */ l = lbc + 7; /* "^SBC=" + value + "\r" + null byte */ if (lhlc) l += lhlc + 7; /* ";^SHLC=" + value */ commands[AT_BC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_BC]) goto oom; strcpy(commands[AT_BC], "^SBC="); if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ decode_ie(cmsg->BC, commands[AT_BC] + 5); strcpy(commands[AT_BC] + l - 2, "\r"); } else if (cip2bchlc[cmsg->CIPValue].bc) { l = strlen(cip2bchlc[cmsg->CIPValue].bc) + 7; commands[AT_BC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_BC]) goto oom; snprintf(commands[AT_BC], l, "^SBC=%s\r", else /* BC derived from CIP */ strcpy(commands[AT_BC] + 5, cip2bchlc[cmsg->CIPValue].bc); } /* check/encode parameter: HLC */ if (cmsg->HLC && cmsg->HLC[0]) { /* explicit HLC overrides CIP */ l = 2*cmsg->HLC[0] + 7; commands[AT_HLC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_HLC]) goto oom; strcpy(commands[AT_HLC], "^SHLC="); decode_ie(cmsg->HLC, commands[AT_HLC]+5); strcpy(commands[AT_HLC] + l - 2, "\r"); } else if (cip2bchlc[cmsg->CIPValue].hlc) { l = strlen(cip2bchlc[cmsg->CIPValue].hlc) + 7; commands[AT_HLC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_HLC]) goto oom; snprintf(commands[AT_HLC], l, "^SHLC=%s\r", if (lhlc) { strcpy(commands[AT_BC] + lbc + 5, ";^SHLC="); if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ decode_ie(cmsg->HLC, commands[AT_BC] + lbc + 12); else /* HLC derived from CIP */ strcpy(commands[AT_BC] + lbc + 12, cip2bchlc[cmsg->CIPValue].hlc); } strcpy(commands[AT_BC] + l - 2, "\r"); } else { /* no BC */ if (lhlc) { dev_notice(cs->dev, "%s: cannot set HLC without BC\n", "CONNECT_REQ"); info = CapiIllMessageParmCoding; /* ? */ goto error; } } /* check/encode parameter: B Protocol */ if (cmsg->BProtocol == CAPI_DEFAULT) { Loading @@ -1322,13 +1452,13 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, Loading Loading @@ -1382,7 +1512,6 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } gigaset_schedule_event(cs); ap->connected = APCONN_SETUP; send_conf(iif, ap, skb, CapiSuccess); return; Loading Loading @@ -1410,6 +1539,7 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; struct gigaset_capi_appl *oap; unsigned long flags; int channel; /* decode message */ Loading @@ -1429,12 +1559,24 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, switch (cmsg->Reject) { case 0: /* Accept */ /* drop all competing applications, keep only this one */ for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) if (oap != ap) spin_lock_irqsave(&bcs->aplock, flags); while (bcs->ap != NULL) { oap = bcs->ap; bcs->ap = oap->bcnext; if (oap != ap) { spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); spin_lock_irqsave(&bcs->aplock, flags); } } ap->bcnext = NULL; bcs->ap = ap; spin_unlock_irqrestore(&bcs->aplock, flags); bcs->rx_bufsize = ap->rp.datablklen; dev_kfree_skb(bcs->rx_skb); gigaset_new_rx_skb(bcs); bcs->chstate |= CHS_NOTIFY_LL; /* check/encode B channel protocol */ Loading @@ -1448,13 +1590,13 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); bcs->proto2 = L2_BITSYNC; bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, Loading Loading @@ -1502,31 +1644,45 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, send_disconnect_ind(bcs, ap, 0); /* remove it from the list of listening apps */ spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap == ap) { bcs->ap = ap->bcnext; if (bcs->ap == NULL) if (bcs->ap == NULL) { /* last one: stop ev-layer hupD notifications */ bcs->apconnstate = APCONN_NONE; bcs->chstate &= ~CHS_NOTIFY_LL; } spin_unlock_irqrestore(&bcs->aplock, flags); return; } for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { if (oap->bcnext == ap) { oap->bcnext = oap->bcnext->bcnext; spin_unlock_irqrestore(&bcs->aplock, flags); return; } } spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: application %u not found\n", __func__, ap->id); return; default: /* Reject */ /* drop all competing applications, keep only this one */ for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) if (oap != ap) spin_lock_irqsave(&bcs->aplock, flags); while (bcs->ap != NULL) { oap = bcs->ap; bcs->ap = oap->bcnext; if (oap != ap) { spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); spin_lock_irqsave(&bcs->aplock, flags); } } ap->bcnext = NULL; bcs->ap = ap; spin_unlock_irqrestore(&bcs->aplock, flags); /* reject call - will trigger DISCONNECT_IND for this app */ dev_info(cs->dev, "%s: Reject=%x\n", Loading @@ -1549,6 +1705,7 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; int channel; /* decode message */ Loading @@ -1563,9 +1720,10 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } bcs = &cs->bcs[channel-1]; /* mark logical connection active */ ap->connected = APCONN_ACTIVE; bcs->apconnstate = APCONN_ACTIVE; /* build NCCI: always 1 (one B3 connection only) */ cmsg->adr.adrNCCI |= 1 << 16; Loading Loading @@ -1611,7 +1769,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif, if (cmsg->Reject) { /* Reject: clear B3 connect received flag */ ap->connected = APCONN_SETUP; bcs->apconnstate = APCONN_SETUP; /* trigger hangup, causing eventual DISCONNECT_IND */ if (!gigaset_add_event(cs, &bcs->at_state, Loading Loading @@ -1683,11 +1841,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, } /* skip if DISCONNECT_IND already sent */ if (!ap->connected) if (!bcs->apconnstate) return; /* check for active logical connection */ if (ap->connected >= APCONN_ACTIVE) { if (bcs->apconnstate >= APCONN_ACTIVE) { /* * emit DISCONNECT_B3_IND with cause 0x3301 * use separate cmsg structure, as the content of iif->acmsg Loading Loading @@ -1736,6 +1894,7 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; int channel; /* decode message */ Loading @@ -1751,17 +1910,17 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } bcs = &cs->bcs[channel-1]; /* reject if logical connection not active */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } /* trigger hangup, causing eventual DISCONNECT_B3_IND */ if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, EV_HUP, NULL, 0, NULL)) { if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } Loading @@ -1782,11 +1941,14 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, struct sk_buff *skb) { struct cardstate *cs = iif->ctr.driverdata; struct bc_state *bcs; int channel = CAPIMSG_PLCI_PART(skb->data); u16 ncci = CAPIMSG_NCCI_PART(skb->data); u16 msglen = CAPIMSG_LEN(skb->data); u16 datalen = CAPIMSG_DATALEN(skb->data); u16 flags = CAPIMSG_FLAGS(skb->data); u16 msgid = CAPIMSG_MSGID(skb->data); u16 handle = CAPIMSG_HANDLE_REQ(skb->data); /* frequent message, avoid _cmsg overhead */ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data); Loading @@ -1802,6 +1964,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } bcs = &cs->bcs[channel-1]; if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) dev_notice(cs->dev, "%s: unexpected length %d\n", "DATA_B3_REQ", msglen); Loading @@ -1821,7 +1984,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, } /* reject if logical connection not active */ if (ap->connected < APCONN_ACTIVE) { if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } Loading @@ -1832,17 +1995,19 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, skb_pull(skb, msglen); /* pass to device-specific module */ if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { if (cs->ops->send_skb(bcs, skb) < 0) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } /* DATA_B3_CONF reply will be sent by gigaset_skb_sent() */ /* * ToDo: honor unset "delivery confirmation" bit * (send DATA_B3_CONF immediately?) * DATA_B3_CONF will be sent by gigaset_skb_sent() only if "delivery * confirmation" bit is set; otherwise we have to send it now */ if (!(flags & CAPI_FLAGS_DELIVERY_CONFIRMATION)) send_data_b3_conf(cs, &iif->ctr, ap->id, msgid, channel, handle, flags ? CapiFlagsNotSupportedByProtocol : CAPI_NOERROR); } /* Loading