Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14cee8e3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'isdn'



Tilman Schmidt says:

====================
Coverity patches for drivers/isdn

Here's a series of patches for the ISDN CAPI subsystem and the
Gigaset ISDN driver.
Patches 1 to 7 are specific fixes for Coverity warnings.
Patches 8 to 11 fix related problems with the handling of invalid
CAPI command codes I noticed while working on this.
Patch 12 fixes an unrelated problem I noticed during the subsequent
regression tests.
It would be great if these could still be merged.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f787d6c8 86f8ef2c
Loading
Loading
Loading
Loading
+20 −4
Original line number Original line Diff line number Diff line
@@ -506,7 +506,10 @@ static void send_message(capidrv_contr *card, _cmsg *cmsg)
	struct sk_buff *skb;
	struct sk_buff *skb;
	size_t len;
	size_t len;


	capi_cmsg2message(cmsg, cmsg->buf);
	if (capi_cmsg2message(cmsg, cmsg->buf)) {
		printk(KERN_ERR "capidrv::send_message: parser failure\n");
		return;
	}
	len = CAPIMSG_LEN(cmsg->buf);
	len = CAPIMSG_LEN(cmsg->buf);
	skb = alloc_skb(len, GFP_ATOMIC);
	skb = alloc_skb(len, GFP_ATOMIC);
	if (!skb) {
	if (!skb) {
@@ -1578,7 +1581,12 @@ static _cmsg s_cmsg;


static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{
{
	capi_message2cmsg(&s_cmsg, skb->data);
	if (capi_message2cmsg(&s_cmsg, skb->data)) {
		printk(KERN_ERR "capidrv: applid=%d: received invalid message\n",
		       ap->applid);
		kfree_skb(skb);
		return;
	}
	if (debugmode > 3) {
	if (debugmode > 3) {
		_cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
		_cdebbuf *cdb = capi_cmsg2str(&s_cmsg);


@@ -1903,7 +1911,11 @@ static int capidrv_command(isdn_ctrl *c, capidrv_contr *card)
				       NULL,	/* Useruserdata */
				       NULL,	/* Useruserdata */
				       NULL	/* Facilitydataarray */
				       NULL	/* Facilitydataarray */
			);
			);
		capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
		if (capi_cmsg2message(&cmdcmsg, cmdcmsg.buf)) {
			printk(KERN_ERR "capidrv-%d: capidrv_command: parser failure\n",
			       card->contrnr);
			return -EINVAL;
		}
		plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
		plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
		send_message(card, &cmdcmsg);
		send_message(card, &cmdcmsg);
		return 0;
		return 0;
@@ -2090,7 +2102,11 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
	if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
	if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
		return 0;
		return 0;


	capi_cmsg2message(&sendcmsg, sendcmsg.buf);
	if (capi_cmsg2message(&sendcmsg, sendcmsg.buf)) {
		printk(KERN_ERR "capidrv-%d: if_sendbuf: parser failure\n",
		       card->contrnr);
		return -EINVAL;
	}
	msglen = CAPIMSG_LEN(sendcmsg.buf);
	msglen = CAPIMSG_LEN(sendcmsg.buf);
	if (skb_headroom(skb) < msglen) {
	if (skb_headroom(skb) < msglen) {
		struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
		struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
+34 −7
Original line number Original line Diff line number Diff line
@@ -207,9 +207,24 @@ static unsigned command_2_index(unsigned c, unsigned sc)
		c = 0x9 + (c & 0x0f);
		c = 0x9 + (c & 0x0f);
	else if (c == 0x41)
	else if (c == 0x41)
		c = 0x9 + 0x1;
		c = 0x9 + 0x1;
	if (c > 0x18)
		c = 0x00;
	return (sc & 3) * (0x9 + 0x9) + c;
	return (sc & 3) * (0x9 + 0x9) + c;
}
}


/**
 * capi_cmd2par() - find parameter string for CAPI 2.0 command/subcommand
 * @cmd:	command number
 * @subcmd:	subcommand number
 *
 * Return value: static string, NULL if command/subcommand unknown
 */

static unsigned char *capi_cmd2par(u8 cmd, u8 subcmd)
{
	return cpars[command_2_index(cmd, subcmd)];
}

/*-------------------------------------------------------*/
/*-------------------------------------------------------*/
#define TYP (cdef[cmsg->par[cmsg->p]].typ)
#define TYP (cdef[cmsg->par[cmsg->p]].typ)
#define OFF (((u8 *)cmsg) + cdef[cmsg->par[cmsg->p]].off)
#define OFF (((u8 *)cmsg) + cdef[cmsg->par[cmsg->p]].off)
@@ -302,7 +317,9 @@ unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg)
	cmsg->m = msg;
	cmsg->m = msg;
	cmsg->l = 8;
	cmsg->l = 8;
	cmsg->p = 0;
	cmsg->p = 0;
	cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
	cmsg->par = capi_cmd2par(cmsg->Command, cmsg->Subcommand);
	if (!cmsg->par)
		return 1;	/* invalid command/subcommand */


	pars_2_message(cmsg);
	pars_2_message(cmsg);


@@ -375,7 +392,9 @@ unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg)
	cmsg->p = 0;
	cmsg->p = 0;
	byteTRcpy(cmsg->m + 4, &cmsg->Command);
	byteTRcpy(cmsg->m + 4, &cmsg->Command);
	byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
	byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
	cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
	cmsg->par = capi_cmd2par(cmsg->Command, cmsg->Subcommand);
	if (!cmsg->par)
		return 1;	/* invalid command/subcommand */


	message_2_pars(cmsg);
	message_2_pars(cmsg);


@@ -470,12 +489,17 @@ static char *mnames[] =
 * @cmd:	command number
 * @cmd:	command number
 * @subcmd:	subcommand number
 * @subcmd:	subcommand number
 *
 *
 * Return value: static string, NULL if command/subcommand unknown
 * Return value: static string
 */
 */


char *capi_cmd2str(u8 cmd, u8 subcmd)
char *capi_cmd2str(u8 cmd, u8 subcmd)
{
{
	return mnames[command_2_index(cmd, subcmd)];
	char *result;

	result = mnames[command_2_index(cmd, subcmd)];
	if (result == NULL)
		result = "INVALID_COMMAND";
	return result;
}
}




@@ -625,6 +649,9 @@ static _cdebbuf *printstruct(_cdebbuf *cdb, u8 *m)


static _cdebbuf *protocol_message_2_pars(_cdebbuf *cdb, _cmsg *cmsg, int level)
static _cdebbuf *protocol_message_2_pars(_cdebbuf *cdb, _cmsg *cmsg, int level)
{
{
	if (!cmsg->par)
		return NULL;	/* invalid command/subcommand */

	for (; TYP != _CEND; cmsg->p++) {
	for (; TYP != _CEND; cmsg->p++) {
		int slen = 29 + 3 - level;
		int slen = 29 + 3 - level;
		int i;
		int i;
@@ -759,10 +786,10 @@ _cdebbuf *capi_message2str(u8 *msg)
	cmsg->p = 0;
	cmsg->p = 0;
	byteTRcpy(cmsg->m + 4, &cmsg->Command);
	byteTRcpy(cmsg->m + 4, &cmsg->Command);
	byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
	byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
	cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
	cmsg->par = capi_cmd2par(cmsg->Command, cmsg->Subcommand);


	cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n",
	cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n",
		       mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
		       ((unsigned short *) msg)[1],
		       ((unsigned short *) msg)[1],
		       ((unsigned short *) msg)[3],
		       ((unsigned short *) msg)[3],
		       ((unsigned short *) msg)[0]);
		       ((unsigned short *) msg)[0]);
@@ -796,7 +823,7 @@ _cdebbuf *capi_cmsg2str(_cmsg *cmsg)
	cmsg->l = 8;
	cmsg->l = 8;
	cmsg->p = 0;
	cmsg->p = 0;
	cdb = bufprint(cdb, "%s ID=%03d #0x%04x LEN=%04d\n",
	cdb = bufprint(cdb, "%s ID=%03d #0x%04x LEN=%04d\n",
		       mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
		       ((u16 *) cmsg->m)[1],
		       ((u16 *) cmsg->m)[1],
		       ((u16 *) cmsg->m)[3],
		       ((u16 *) cmsg->m)[3],
		       ((u16 *) cmsg->m)[0]);
		       ((u16 *) cmsg->m)[0]);
+2 −2
Original line number Original line Diff line number Diff line
@@ -1184,7 +1184,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
 * Return value: CAPI result code
 * Return value: CAPI result code
 */
 */


int capi20_manufacturer(unsigned int cmd, void __user *data)
int capi20_manufacturer(unsigned long cmd, void __user *data)
{
{
	struct capi_ctr *ctr;
	struct capi_ctr *ctr;
	int retval;
	int retval;
@@ -1259,7 +1259,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
	}
	}


	default:
	default:
		printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
		printk(KERN_ERR "kcapi: manufacturer command %lu unknown.\n",
		       cmd);
		       cmd);
		break;
		break;


+130 −25
Original line number Original line Diff line number Diff line
@@ -250,6 +250,8 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag,
	l -= 12;
	l -= 12;
	if (l <= 0)
	if (l <= 0)
		return;
		return;
	if (l > 64)
		l = 64; /* arbitrary limit */
	dbgline = kmalloc(3 * l, GFP_ATOMIC);
	dbgline = kmalloc(3 * l, GFP_ATOMIC);
	if (!dbgline)
	if (!dbgline)
		return;
		return;
@@ -645,7 +647,13 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
					__func__);
					__func__);
				break;
				break;
			}
			}
			capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));
			if (capi_cmsg2message(&iif->hcmsg,
					      __skb_put(skb, msgsize))) {
				dev_err(cs->dev, "%s: message parser failure\n",
					__func__);
				dev_kfree_skb_any(skb);
				break;
			}
			dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
			dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);


			/* add to listeners on this B channel, update state */
			/* add to listeners on this B channel, update state */
@@ -691,7 +699,12 @@ static void send_disconnect_ind(struct bc_state *bcs,
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		return;
		return;
	}
	}
	capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN));
	if (capi_cmsg2message(&iif->hcmsg,
			      __skb_put(skb, CAPI_DISCONNECT_IND_LEN))) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
}
}
@@ -721,8 +734,12 @@ static void send_disconnect_b3_ind(struct bc_state *bcs,
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		return;
		return;
	}
	}
	capi_cmsg2message(&iif->hcmsg,
	if (capi_cmsg2message(&iif->hcmsg,
			  __skb_put(skb, CAPI_DISCONNECT_B3_IND_BASELEN));
			  __skb_put(skb, CAPI_DISCONNECT_B3_IND_BASELEN))) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
}
}
@@ -787,7 +804,11 @@ void gigaset_isdn_connD(struct bc_state *bcs)
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		return;
		return;
	}
	}
	capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));
	if (capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize))) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
}
}
@@ -887,7 +908,11 @@ void gigaset_isdn_connB(struct bc_state *bcs)
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		return;
		return;
	}
	}
	capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));
	if (capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize))) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
}
}
@@ -1094,13 +1119,19 @@ static void send_conf(struct gigaset_capi_ctr *iif,
		      struct sk_buff *skb,
		      struct sk_buff *skb,
		      u16 info)
		      u16 info)
{
{
	struct cardstate *cs = iif->ctr.driverdata;

	/*
	/*
	 * _CONF replies always only have NCCI and Info parameters
	 * _CONF replies always only have NCCI and Info parameters
	 * so they'll fit into the _REQ message skb
	 * so they'll fit into the _REQ message skb
	 */
	 */
	capi_cmsg_answer(&iif->acmsg);
	capi_cmsg_answer(&iif->acmsg);
	iif->acmsg.Info = info;
	iif->acmsg.Info = info;
	capi_cmsg2message(&iif->acmsg, skb->data);
	if (capi_cmsg2message(&iif->acmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	__skb_trim(skb, CAPI_STDCONF_LEN);
	__skb_trim(skb, CAPI_STDCONF_LEN);
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
@@ -1122,7 +1153,11 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
	static u8 confparam[10];	/* max. 9 octets + length byte */
	static u8 confparam[10];	/* max. 9 octets + length byte */


	/* decode message */
	/* decode message */
	capi_message2cmsg(cmsg, skb->data);
	if (capi_message2cmsg(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);


	/*
	/*
@@ -1180,6 +1215,7 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
				confparam[3] = 2;	/* length */
				confparam[3] = 2;	/* length */
				capimsg_setu16(confparam, 4,
				capimsg_setu16(confparam, 4,
					       CapiSupplementaryServiceNotSupported);
					       CapiSupplementaryServiceNotSupported);
				break;
			}
			}
			info = CapiSuccess;
			info = CapiSuccess;
			confparam[3] = 2;	/* length */
			confparam[3] = 2;	/* length */
@@ -1220,6 +1256,7 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
	}
	}


	/* send FACILITY_CONF with given Info and confirmation parameter */
	/* send FACILITY_CONF with given Info and confirmation parameter */
	dev_kfree_skb_any(skb);
	capi_cmsg_answer(cmsg);
	capi_cmsg_answer(cmsg);
	cmsg->Info = info;
	cmsg->Info = info;
	cmsg->FacilityConfirmationParameter = confparam;
	cmsg->FacilityConfirmationParameter = confparam;
@@ -1229,7 +1266,11 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		dev_err(cs->dev, "%s: out of memory\n", __func__);
		return;
		return;
	}
	}
	capi_cmsg2message(cmsg, __skb_put(cskb, msgsize));
	if (capi_cmsg2message(cmsg, __skb_put(cskb, msgsize))) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(cskb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	capi_ctr_handle_message(&iif->ctr, ap->id, cskb);
	capi_ctr_handle_message(&iif->ctr, ap->id, cskb);
}
}
@@ -1243,8 +1284,14 @@ static void do_listen_req(struct gigaset_capi_ctr *iif,
			  struct gigaset_capi_appl *ap,
			  struct gigaset_capi_appl *ap,
			  struct sk_buff *skb)
			  struct sk_buff *skb)
{
{
	struct cardstate *cs = iif->ctr.driverdata;

	/* decode message */
	/* decode message */
	capi_message2cmsg(&iif->acmsg, skb->data);
	if (capi_message2cmsg(&iif->acmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);


	/* store listening parameters */
	/* store listening parameters */
@@ -1261,8 +1308,14 @@ static void do_alert_req(struct gigaset_capi_ctr *iif,
			 struct gigaset_capi_appl *ap,
			 struct gigaset_capi_appl *ap,
			 struct sk_buff *skb)
			 struct sk_buff *skb)
{
{
	struct cardstate *cs = iif->ctr.driverdata;

	/* decode message */
	/* decode message */
	capi_message2cmsg(&iif->acmsg, skb->data);
	if (capi_message2cmsg(&iif->acmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	send_conf(iif, ap, skb, CapiAlertAlreadySent);
	send_conf(iif, ap, skb, CapiAlertAlreadySent);
}
}
@@ -1287,7 +1340,11 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
	u16 info;
	u16 info;


	/* decode message */
	/* decode message */
	capi_message2cmsg(cmsg, skb->data);
	if (capi_message2cmsg(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);


	/* get free B channel & construct PLCI */
	/* get free B channel & construct PLCI */
@@ -1574,7 +1631,11 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
	int channel;
	int channel;


	/* decode message */
	/* decode message */
	capi_message2cmsg(cmsg, skb->data);
	if (capi_message2cmsg(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dev_kfree_skb_any(skb);
	dev_kfree_skb_any(skb);


@@ -1740,7 +1801,11 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif,
	int channel;
	int channel;


	/* decode message */
	/* decode message */
	capi_message2cmsg(cmsg, skb->data);
	if (capi_message2cmsg(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);


	/* extract and check channel number from PLCI */
	/* extract and check channel number from PLCI */
@@ -1785,7 +1850,11 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
	u8 command;
	u8 command;


	/* decode message */
	/* decode message */
	capi_message2cmsg(cmsg, skb->data);
	if (capi_message2cmsg(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);


	/* extract and check channel number and NCCI */
	/* extract and check channel number and NCCI */
@@ -1825,7 +1894,11 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
	capi_cmsg_header(cmsg, ap->id, command, CAPI_IND,
	capi_cmsg_header(cmsg, ap->id, command, CAPI_IND,
			 ap->nextMessageNumber++, cmsg->adr.adrNCCI);
			 ap->nextMessageNumber++, cmsg->adr.adrNCCI);
	__skb_trim(skb, msgsize);
	__skb_trim(skb, msgsize);
	capi_cmsg2message(cmsg, skb->data);
	if (capi_cmsg2message(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
	capi_ctr_handle_message(&iif->ctr, ap->id, skb);
}
}
@@ -1847,7 +1920,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
	int channel;
	int channel;


	/* decode message */
	/* decode message */
	capi_message2cmsg(cmsg, skb->data);
	if (capi_message2cmsg(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);


	/* extract and check channel number from PLCI */
	/* extract and check channel number from PLCI */
@@ -1903,8 +1980,14 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
			kfree(b3cmsg);
			kfree(b3cmsg);
			return;
			return;
		}
		}
		capi_cmsg2message(b3cmsg,
		if (capi_cmsg2message(b3cmsg,
				  __skb_put(b3skb, CAPI_DISCONNECT_B3_IND_BASELEN));
				      __skb_put(b3skb, CAPI_DISCONNECT_B3_IND_BASELEN))) {
			dev_err(cs->dev, "%s: message parser failure\n",
				__func__);
			kfree(b3cmsg);
			dev_kfree_skb_any(b3skb);
			return;
		}
		dump_cmsg(DEBUG_CMD, __func__, b3cmsg);
		dump_cmsg(DEBUG_CMD, __func__, b3cmsg);
		kfree(b3cmsg);
		kfree(b3cmsg);
		capi_ctr_handle_message(&iif->ctr, ap->id, b3skb);
		capi_ctr_handle_message(&iif->ctr, ap->id, b3skb);
@@ -1935,7 +2018,11 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,
	int channel;
	int channel;


	/* decode message */
	/* decode message */
	capi_message2cmsg(cmsg, skb->data);
	if (capi_message2cmsg(cmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, cmsg);
	dump_cmsg(DEBUG_CMD, __func__, cmsg);


	/* extract and check channel number and NCCI */
	/* extract and check channel number and NCCI */
@@ -2052,8 +2139,14 @@ static void do_reset_b3_req(struct gigaset_capi_ctr *iif,
			    struct gigaset_capi_appl *ap,
			    struct gigaset_capi_appl *ap,
			    struct sk_buff *skb)
			    struct sk_buff *skb)
{
{
	struct cardstate *cs = iif->ctr.driverdata;

	/* decode message */
	/* decode message */
	capi_message2cmsg(&iif->acmsg, skb->data);
	if (capi_message2cmsg(&iif->acmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	send_conf(iif, ap, skb,
	send_conf(iif, ap, skb,
		  CapiResetProcedureNotSupportedByCurrentProtocol);
		  CapiResetProcedureNotSupportedByCurrentProtocol);
@@ -2066,8 +2159,14 @@ static void do_unsupported(struct gigaset_capi_ctr *iif,
			   struct gigaset_capi_appl *ap,
			   struct gigaset_capi_appl *ap,
			   struct sk_buff *skb)
			   struct sk_buff *skb)
{
{
	struct cardstate *cs = iif->ctr.driverdata;

	/* decode message */
	/* decode message */
	capi_message2cmsg(&iif->acmsg, skb->data);
	if (capi_message2cmsg(&iif->acmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState);
	send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState);
}
}
@@ -2079,8 +2178,14 @@ static void do_nothing(struct gigaset_capi_ctr *iif,
		       struct gigaset_capi_appl *ap,
		       struct gigaset_capi_appl *ap,
		       struct sk_buff *skb)
		       struct sk_buff *skb)
{
{
	struct cardstate *cs = iif->ctr.driverdata;

	/* decode message */
	/* decode message */
	capi_message2cmsg(&iif->acmsg, skb->data);
	if (capi_message2cmsg(&iif->acmsg, skb->data)) {
		dev_err(cs->dev, "%s: message parser failure\n", __func__);
		dev_kfree_skb_any(skb);
		return;
	}
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
	dev_kfree_skb_any(skb);
	dev_kfree_skb_any(skb);
}
}
@@ -2357,7 +2462,7 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
	struct gigaset_capi_ctr *iif;
	struct gigaset_capi_ctr *iif;
	int rc;
	int rc;


	iif = kmalloc(sizeof(*iif), GFP_KERNEL);
	iif = kzalloc(sizeof(*iif), GFP_KERNEL);
	if (!iif) {
	if (!iif) {
		pr_err("%s: out of memory\n", __func__);
		pr_err("%s: out of memory\n", __func__);
		return -ENOMEM;
		return -ENOMEM;
@@ -2366,7 +2471,7 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
	/* prepare controller structure */
	/* prepare controller structure */
	iif->ctr.owner         = THIS_MODULE;
	iif->ctr.owner         = THIS_MODULE;
	iif->ctr.driverdata    = cs;
	iif->ctr.driverdata    = cs;
	strncpy(iif->ctr.name, isdnid, sizeof(iif->ctr.name));
	strncpy(iif->ctr.name, isdnid, sizeof(iif->ctr.name) - 1);
	iif->ctr.driver_name   = "gigaset";
	iif->ctr.driver_name   = "gigaset";
	iif->ctr.load_firmware = NULL;
	iif->ctr.load_firmware = NULL;
	iif->ctr.reset_ctr     = NULL;
	iif->ctr.reset_ctr     = NULL;
+75 −41
Original line number Original line Diff line number Diff line
@@ -604,14 +604,14 @@ void gigaset_handle_modem_response(struct cardstate *cs)
}
}
EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);
EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);


/* disconnect
/* disconnect_nobc
 * process closing of connection associated with given AT state structure
 * process closing of connection associated with given AT state structure
 * without B channel
 */
 */
static void disconnect(struct at_state_t **at_state_p)
static void disconnect_nobc(struct at_state_t **at_state_p,
			    struct cardstate *cs)
{
{
	unsigned long flags;
	unsigned long flags;
	struct bc_state *bcs = (*at_state_p)->bcs;
	struct cardstate *cs = (*at_state_p)->cs;


	spin_lock_irqsave(&cs->lock, flags);
	spin_lock_irqsave(&cs->lock, flags);
	++(*at_state_p)->seq_index;
	++(*at_state_p)->seq_index;
@@ -622,31 +622,52 @@ static void disconnect(struct at_state_t **at_state_p)
		gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE");
		gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE");
		cs->commands_pending = 1;
		cs->commands_pending = 1;
	}
	}

	/* check for and deallocate temporary AT state */
	if (!list_empty(&(*at_state_p)->list)) {
		list_del(&(*at_state_p)->list);
		kfree(*at_state_p);
		*at_state_p = NULL;
	}

	spin_unlock_irqrestore(&cs->lock, flags);
	spin_unlock_irqrestore(&cs->lock, flags);
}


	if (bcs) {
/* disconnect_bc
		/* B channel assigned: invoke hardware specific handler */
 * process closing of connection associated with given AT state structure
 * and B channel
 */
static void disconnect_bc(struct at_state_t *at_state,
			  struct cardstate *cs, struct bc_state *bcs)
{
	unsigned long flags;

	spin_lock_irqsave(&cs->lock, flags);
	++at_state->seq_index;

	/* revert to selected idle mode */
	if (!cs->cidmode) {
		cs->at_state.pending_commands |= PC_UMMODE;
		gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE");
		cs->commands_pending = 1;
	}
	spin_unlock_irqrestore(&cs->lock, flags);

	/* invoke hardware specific handler */
	cs->ops->close_bchannel(bcs);
	cs->ops->close_bchannel(bcs);

	/* notify LL */
	/* notify LL */
	if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
	if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
		bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
		bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
		gigaset_isdn_hupD(bcs);
		gigaset_isdn_hupD(bcs);
	}
	}
	} else {
		/* no B channel assigned: just deallocate */
		spin_lock_irqsave(&cs->lock, flags);
		list_del(&(*at_state_p)->list);
		kfree(*at_state_p);
		*at_state_p = NULL;
		spin_unlock_irqrestore(&cs->lock, flags);
	}
}
}


/* get_free_channel
/* get_free_channel
 * get a free AT state structure: either one of those associated with the
 * get a free AT state structure: either one of those associated with the
 * B channels of the Gigaset device, or if none of those is available,
 * B channels of the Gigaset device, or if none of those is available,
 * a newly allocated one with bcs=NULL
 * a newly allocated one with bcs=NULL
 * The structure should be freed by calling disconnect() after use.
 * The structure should be freed by calling disconnect_nobc() after use.
 */
 */
static inline struct at_state_t *get_free_channel(struct cardstate *cs,
static inline struct at_state_t *get_free_channel(struct cardstate *cs,
						  int cid)
						  int cid)
@@ -1057,7 +1078,7 @@ static void do_action(int action, struct cardstate *cs,
		      struct event_t *ev)
		      struct event_t *ev)
{
{
	struct at_state_t *at_state = *p_at_state;
	struct at_state_t *at_state = *p_at_state;
	struct at_state_t *at_state2;
	struct bc_state *bcs2;
	unsigned long flags;
	unsigned long flags;


	int channel;
	int channel;
@@ -1156,8 +1177,8 @@ static void do_action(int action, struct cardstate *cs,
		break;
		break;
	case ACT_RING:
	case ACT_RING:
		/* get fresh AT state structure for new CID */
		/* get fresh AT state structure for new CID */
		at_state2 = get_free_channel(cs, ev->parameter);
		at_state = get_free_channel(cs, ev->parameter);
		if (!at_state2) {
		if (!at_state) {
			dev_warn(cs->dev,
			dev_warn(cs->dev,
				 "RING ignored: could not allocate channel structure\n");
				 "RING ignored: could not allocate channel structure\n");
			break;
			break;
@@ -1166,16 +1187,16 @@ static void do_action(int action, struct cardstate *cs,
		/* initialize AT state structure
		/* initialize AT state structure
		 * note that bcs may be NULL if no B channel is free
		 * note that bcs may be NULL if no B channel is free
		 */
		 */
		at_state2->ConState = 700;
		at_state->ConState = 700;
		for (i = 0; i < STR_NUM; ++i) {
		for (i = 0; i < STR_NUM; ++i) {
			kfree(at_state2->str_var[i]);
			kfree(at_state->str_var[i]);
			at_state2->str_var[i] = NULL;
			at_state->str_var[i] = NULL;
		}
		}
		at_state2->int_var[VAR_ZCTP] = -1;
		at_state->int_var[VAR_ZCTP] = -1;


		spin_lock_irqsave(&cs->lock, flags);
		spin_lock_irqsave(&cs->lock, flags);
		at_state2->timer_expires = RING_TIMEOUT;
		at_state->timer_expires = RING_TIMEOUT;
		at_state2->timer_active = 1;
		at_state->timer_active = 1;
		spin_unlock_irqrestore(&cs->lock, flags);
		spin_unlock_irqrestore(&cs->lock, flags);
		break;
		break;
	case ACT_ICALL:
	case ACT_ICALL:
@@ -1213,14 +1234,17 @@ static void do_action(int action, struct cardstate *cs,
	case ACT_DISCONNECT:
	case ACT_DISCONNECT:
		cs->cur_at_seq = SEQ_NONE;
		cs->cur_at_seq = SEQ_NONE;
		at_state->cid = -1;
		at_state->cid = -1;
		if (bcs && cs->onechannel && cs->dle) {
		if (!bcs) {
			disconnect_nobc(p_at_state, cs);
		} else if (cs->onechannel && cs->dle) {
			/* Check for other open channels not needed:
			/* Check for other open channels not needed:
			 * DLE only used for M10x with one B channel.
			 * DLE only used for M10x with one B channel.
			 */
			 */
			at_state->pending_commands |= PC_DLE0;
			at_state->pending_commands |= PC_DLE0;
			cs->commands_pending = 1;
			cs->commands_pending = 1;
		} else
		} else {
			disconnect(p_at_state);
			disconnect_bc(at_state, cs, bcs);
		}
		break;
		break;
	case ACT_FAKEDLE0:
	case ACT_FAKEDLE0:
		at_state->int_var[VAR_ZDLE] = 0;
		at_state->int_var[VAR_ZDLE] = 0;
@@ -1228,25 +1252,27 @@ static void do_action(int action, struct cardstate *cs,
		/* fall through */
		/* fall through */
	case ACT_DLE0:
	case ACT_DLE0:
		cs->cur_at_seq = SEQ_NONE;
		cs->cur_at_seq = SEQ_NONE;
		at_state2 = &cs->bcs[cs->curchannel].at_state;
		bcs2 = cs->bcs + cs->curchannel;
		disconnect(&at_state2);
		disconnect_bc(&bcs2->at_state, cs, bcs2);
		break;
		break;
	case ACT_ABORTHUP:
	case ACT_ABORTHUP:
		cs->cur_at_seq = SEQ_NONE;
		cs->cur_at_seq = SEQ_NONE;
		dev_warn(cs->dev, "Could not hang up.\n");
		dev_warn(cs->dev, "Could not hang up.\n");
		at_state->cid = -1;
		at_state->cid = -1;
		if (bcs && cs->onechannel)
		if (!bcs)
			disconnect_nobc(p_at_state, cs);
		else if (cs->onechannel)
			at_state->pending_commands |= PC_DLE0;
			at_state->pending_commands |= PC_DLE0;
		else
		else
			disconnect(p_at_state);
			disconnect_bc(at_state, cs, bcs);
		schedule_init(cs, MS_RECOVER);
		schedule_init(cs, MS_RECOVER);
		break;
		break;
	case ACT_FAILDLE0:
	case ACT_FAILDLE0:
		cs->cur_at_seq = SEQ_NONE;
		cs->cur_at_seq = SEQ_NONE;
		dev_warn(cs->dev, "Error leaving DLE mode.\n");
		dev_warn(cs->dev, "Error leaving DLE mode.\n");
		cs->dle = 0;
		cs->dle = 0;
		at_state2 = &cs->bcs[cs->curchannel].at_state;
		bcs2 = cs->bcs + cs->curchannel;
		disconnect(&at_state2);
		disconnect_bc(&bcs2->at_state, cs, bcs2);
		schedule_init(cs, MS_RECOVER);
		schedule_init(cs, MS_RECOVER);
		break;
		break;
	case ACT_FAILDLE1:
	case ACT_FAILDLE1:
@@ -1275,14 +1301,14 @@ static void do_action(int action, struct cardstate *cs,
		if (reinit_and_retry(cs, channel) < 0) {
		if (reinit_and_retry(cs, channel) < 0) {
			dev_warn(cs->dev,
			dev_warn(cs->dev,
				 "Could not get a call ID. Cannot dial.\n");
				 "Could not get a call ID. Cannot dial.\n");
			at_state2 = &cs->bcs[channel].at_state;
			bcs2 = cs->bcs + channel;
			disconnect(&at_state2);
			disconnect_bc(&bcs2->at_state, cs, bcs2);
		}
		}
		break;
		break;
	case ACT_ABORTCID:
	case ACT_ABORTCID:
		cs->cur_at_seq = SEQ_NONE;
		cs->cur_at_seq = SEQ_NONE;
		at_state2 = &cs->bcs[cs->curchannel].at_state;
		bcs2 = cs->bcs + cs->curchannel;
		disconnect(&at_state2);
		disconnect_bc(&bcs2->at_state, cs, bcs2);
		break;
		break;


	case ACT_DIALING:
	case ACT_DIALING:
@@ -1291,7 +1317,10 @@ static void do_action(int action, struct cardstate *cs,
		break;
		break;


	case ACT_ABORTACCEPT:	/* hangup/error/timeout during ICALL procssng */
	case ACT_ABORTACCEPT:	/* hangup/error/timeout during ICALL procssng */
		disconnect(p_at_state);
		if (bcs)
			disconnect_bc(at_state, cs, bcs);
		else
			disconnect_nobc(p_at_state, cs);
		break;
		break;


	case ACT_ABORTDIAL:	/* error/timeout during dial preparation */
	case ACT_ABORTDIAL:	/* error/timeout during dial preparation */
@@ -1380,6 +1409,11 @@ static void do_action(int action, struct cardstate *cs,
	/* events from the LL */
	/* events from the LL */


	case ACT_DIAL:
	case ACT_DIAL:
		if (!ev->ptr) {
			*p_genresp = 1;
			*p_resp_code = RSP_ERROR;
			break;
		}
		start_dial(at_state, ev->ptr, ev->parameter);
		start_dial(at_state, ev->ptr, ev->parameter);
		break;
		break;
	case ACT_ACCEPT:
	case ACT_ACCEPT:
Loading