brintos

brintos / linux-shallow public Read only

0
0
Text · 11.6 KiB · 8c93af0 Raw
517 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 * Author	Karsten Keil <kkeil@novell.com>5 *6 * Copyright 2008  by Karsten Keil <kkeil@novell.com>7 */8 9#include <linux/gfp.h>10#include <linux/module.h>11#include <linux/mISDNhw.h>12 13static void14dchannel_bh(struct work_struct *ws)15{16	struct dchannel	*dch  = container_of(ws, struct dchannel, workq);17	struct sk_buff	*skb;18	int		err;19 20	if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) {21		while ((skb = skb_dequeue(&dch->rqueue))) {22			if (likely(dch->dev.D.peer)) {23				err = dch->dev.D.recv(dch->dev.D.peer, skb);24				if (err)25					dev_kfree_skb(skb);26			} else27				dev_kfree_skb(skb);28		}29	}30	if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) {31		if (dch->phfunc)32			dch->phfunc(dch);33	}34}35 36static void37bchannel_bh(struct work_struct *ws)38{39	struct bchannel	*bch  = container_of(ws, struct bchannel, workq);40	struct sk_buff	*skb;41	int		err;42 43	if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) {44		while ((skb = skb_dequeue(&bch->rqueue))) {45			bch->rcount--;46			if (likely(bch->ch.peer)) {47				err = bch->ch.recv(bch->ch.peer, skb);48				if (err)49					dev_kfree_skb(skb);50			} else51				dev_kfree_skb(skb);52		}53	}54}55 56int57mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf)58{59	test_and_set_bit(FLG_HDLC, &ch->Flags);60	ch->maxlen = maxlen;61	ch->hw = NULL;62	ch->rx_skb = NULL;63	ch->tx_skb = NULL;64	ch->tx_idx = 0;65	ch->phfunc = phf;66	skb_queue_head_init(&ch->squeue);67	skb_queue_head_init(&ch->rqueue);68	INIT_LIST_HEAD(&ch->dev.bchannels);69	INIT_WORK(&ch->workq, dchannel_bh);70	return 0;71}72EXPORT_SYMBOL(mISDN_initdchannel);73 74int75mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen,76		   unsigned short minlen)77{78	ch->Flags = 0;79	ch->minlen = minlen;80	ch->next_minlen = minlen;81	ch->init_minlen = minlen;82	ch->maxlen = maxlen;83	ch->next_maxlen = maxlen;84	ch->init_maxlen = maxlen;85	ch->hw = NULL;86	ch->rx_skb = NULL;87	ch->tx_skb = NULL;88	ch->tx_idx = 0;89	skb_queue_head_init(&ch->rqueue);90	ch->rcount = 0;91	ch->next_skb = NULL;92	INIT_WORK(&ch->workq, bchannel_bh);93	return 0;94}95EXPORT_SYMBOL(mISDN_initbchannel);96 97int98mISDN_freedchannel(struct dchannel *ch)99{100	if (ch->tx_skb) {101		dev_kfree_skb(ch->tx_skb);102		ch->tx_skb = NULL;103	}104	if (ch->rx_skb) {105		dev_kfree_skb(ch->rx_skb);106		ch->rx_skb = NULL;107	}108	skb_queue_purge(&ch->squeue);109	skb_queue_purge(&ch->rqueue);110	flush_work(&ch->workq);111	return 0;112}113EXPORT_SYMBOL(mISDN_freedchannel);114 115void116mISDN_clear_bchannel(struct bchannel *ch)117{118	if (ch->tx_skb) {119		dev_kfree_skb(ch->tx_skb);120		ch->tx_skb = NULL;121	}122	ch->tx_idx = 0;123	if (ch->rx_skb) {124		dev_kfree_skb(ch->rx_skb);125		ch->rx_skb = NULL;126	}127	if (ch->next_skb) {128		dev_kfree_skb(ch->next_skb);129		ch->next_skb = NULL;130	}131	test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);132	test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);133	test_and_clear_bit(FLG_ACTIVE, &ch->Flags);134	test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags);135	test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags);136	test_and_clear_bit(FLG_RX_OFF, &ch->Flags);137	ch->dropcnt = 0;138	ch->minlen = ch->init_minlen;139	ch->next_minlen = ch->init_minlen;140	ch->maxlen = ch->init_maxlen;141	ch->next_maxlen = ch->init_maxlen;142	skb_queue_purge(&ch->rqueue);143	ch->rcount = 0;144}145EXPORT_SYMBOL(mISDN_clear_bchannel);146 147void148mISDN_freebchannel(struct bchannel *ch)149{150	cancel_work_sync(&ch->workq);151	mISDN_clear_bchannel(ch);152}153EXPORT_SYMBOL(mISDN_freebchannel);154 155int156mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)157{158	int ret = 0;159 160	switch (cq->op) {161	case MISDN_CTRL_GETOP:162		cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY |163			 MISDN_CTRL_RX_OFF;164		break;165	case MISDN_CTRL_FILL_EMPTY:166		if (cq->p1) {167			memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE);168			test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);169		} else {170			test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);171		}172		break;173	case MISDN_CTRL_RX_OFF:174		/* read back dropped byte count */175		cq->p2 = bch->dropcnt;176		if (cq->p1)177			test_and_set_bit(FLG_RX_OFF, &bch->Flags);178		else179			test_and_clear_bit(FLG_RX_OFF, &bch->Flags);180		bch->dropcnt = 0;181		break;182	case MISDN_CTRL_RX_BUFFER:183		if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE)184			bch->next_maxlen = cq->p2;185		if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE)186			bch->next_minlen = cq->p1;187		/* we return the old values */188		cq->p1 = bch->minlen;189		cq->p2 = bch->maxlen;190		break;191	default:192		pr_info("mISDN unhandled control %x operation\n", cq->op);193		ret = -EINVAL;194		break;195	}196	return ret;197}198EXPORT_SYMBOL(mISDN_ctrl_bchannel);199 200static inline u_int201get_sapi_tei(u_char *p)202{203	u_int	sapi, tei;204 205	sapi = *p >> 2;206	tei = p[1] >> 1;207	return sapi | (tei << 8);208}209 210void211recv_Dchannel(struct dchannel *dch)212{213	struct mISDNhead *hh;214 215	if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */216		dev_kfree_skb(dch->rx_skb);217		dch->rx_skb = NULL;218		return;219	}220	hh = mISDN_HEAD_P(dch->rx_skb);221	hh->prim = PH_DATA_IND;222	hh->id = get_sapi_tei(dch->rx_skb->data);223	skb_queue_tail(&dch->rqueue, dch->rx_skb);224	dch->rx_skb = NULL;225	schedule_event(dch, FLG_RECVQUEUE);226}227EXPORT_SYMBOL(recv_Dchannel);228 229void230recv_Echannel(struct dchannel *ech, struct dchannel *dch)231{232	struct mISDNhead *hh;233 234	if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */235		dev_kfree_skb(ech->rx_skb);236		ech->rx_skb = NULL;237		return;238	}239	hh = mISDN_HEAD_P(ech->rx_skb);240	hh->prim = PH_DATA_E_IND;241	hh->id = get_sapi_tei(ech->rx_skb->data);242	skb_queue_tail(&dch->rqueue, ech->rx_skb);243	ech->rx_skb = NULL;244	schedule_event(dch, FLG_RECVQUEUE);245}246EXPORT_SYMBOL(recv_Echannel);247 248void249recv_Bchannel(struct bchannel *bch, unsigned int id, bool force)250{251	struct mISDNhead *hh;252 253	/* if allocation did fail upper functions still may call us */254	if (unlikely(!bch->rx_skb))255		return;256	if (unlikely(!bch->rx_skb->len)) {257		/* we have no data to send - this may happen after recovery258		 * from overflow or too small allocation.259		 * We need to free the buffer here */260		dev_kfree_skb(bch->rx_skb);261		bch->rx_skb = NULL;262	} else {263		if (test_bit(FLG_TRANSPARENT, &bch->Flags) &&264		    (bch->rx_skb->len < bch->minlen) && !force)265				return;266		hh = mISDN_HEAD_P(bch->rx_skb);267		hh->prim = PH_DATA_IND;268		hh->id = id;269		if (bch->rcount >= 64) {270			printk(KERN_WARNING271			       "B%d receive queue overflow - flushing!\n",272			       bch->nr);273			skb_queue_purge(&bch->rqueue);274		}275		bch->rcount++;276		skb_queue_tail(&bch->rqueue, bch->rx_skb);277		bch->rx_skb = NULL;278		schedule_event(bch, FLG_RECVQUEUE);279	}280}281EXPORT_SYMBOL(recv_Bchannel);282 283void284recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb)285{286	skb_queue_tail(&dch->rqueue, skb);287	schedule_event(dch, FLG_RECVQUEUE);288}289EXPORT_SYMBOL(recv_Dchannel_skb);290 291void292recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb)293{294	if (bch->rcount >= 64) {295		printk(KERN_WARNING "B-channel %p receive queue overflow, "296		       "flushing!\n", bch);297		skb_queue_purge(&bch->rqueue);298		bch->rcount = 0;299	}300	bch->rcount++;301	skb_queue_tail(&bch->rqueue, skb);302	schedule_event(bch, FLG_RECVQUEUE);303}304EXPORT_SYMBOL(recv_Bchannel_skb);305 306static void307confirm_Dsend(struct dchannel *dch)308{309	struct sk_buff	*skb;310 311	skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb),312			       0, NULL, GFP_ATOMIC);313	if (!skb) {314		printk(KERN_ERR "%s: no skb id %x\n", __func__,315		       mISDN_HEAD_ID(dch->tx_skb));316		return;317	}318	skb_queue_tail(&dch->rqueue, skb);319	schedule_event(dch, FLG_RECVQUEUE);320}321 322int323get_next_dframe(struct dchannel *dch)324{325	dch->tx_idx = 0;326	dch->tx_skb = skb_dequeue(&dch->squeue);327	if (dch->tx_skb) {328		confirm_Dsend(dch);329		return 1;330	}331	dch->tx_skb = NULL;332	test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);333	return 0;334}335EXPORT_SYMBOL(get_next_dframe);336 337static void338confirm_Bsend(struct bchannel *bch)339{340	struct sk_buff	*skb;341 342	if (bch->rcount >= 64) {343		printk(KERN_WARNING "B-channel %p receive queue overflow, "344		       "flushing!\n", bch);345		skb_queue_purge(&bch->rqueue);346		bch->rcount = 0;347	}348	skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb),349			       0, NULL, GFP_ATOMIC);350	if (!skb) {351		printk(KERN_ERR "%s: no skb id %x\n", __func__,352		       mISDN_HEAD_ID(bch->tx_skb));353		return;354	}355	bch->rcount++;356	skb_queue_tail(&bch->rqueue, skb);357	schedule_event(bch, FLG_RECVQUEUE);358}359 360int361get_next_bframe(struct bchannel *bch)362{363	bch->tx_idx = 0;364	if (test_bit(FLG_TX_NEXT, &bch->Flags)) {365		bch->tx_skb = bch->next_skb;366		if (bch->tx_skb) {367			bch->next_skb = NULL;368			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);369			/* confirm imediately to allow next data */370			confirm_Bsend(bch);371			return 1;372		} else {373			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);374			printk(KERN_WARNING "B TX_NEXT without skb\n");375		}376	}377	bch->tx_skb = NULL;378	test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);379	return 0;380}381EXPORT_SYMBOL(get_next_bframe);382 383void384queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb)385{386	struct mISDNhead *hh;387 388	if (!skb) {389		_queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC);390	} else {391		if (ch->peer) {392			hh = mISDN_HEAD_P(skb);393			hh->prim = pr;394			hh->id = id;395			if (!ch->recv(ch->peer, skb))396				return;397		}398		dev_kfree_skb(skb);399	}400}401EXPORT_SYMBOL(queue_ch_frame);402 403int404dchannel_senddata(struct dchannel *ch, struct sk_buff *skb)405{406	/* check oversize */407	if (skb->len <= 0) {408		printk(KERN_WARNING "%s: skb too small\n", __func__);409		return -EINVAL;410	}411	if (skb->len > ch->maxlen) {412		printk(KERN_WARNING "%s: skb too large(%d/%d)\n",413		       __func__, skb->len, ch->maxlen);414		return -EINVAL;415	}416	/* HW lock must be obtained */417	if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {418		skb_queue_tail(&ch->squeue, skb);419		return 0;420	} else {421		/* write to fifo */422		ch->tx_skb = skb;423		ch->tx_idx = 0;424		return 1;425	}426}427EXPORT_SYMBOL(dchannel_senddata);428 429int430bchannel_senddata(struct bchannel *ch, struct sk_buff *skb)431{432 433	/* check oversize */434	if (skb->len <= 0) {435		printk(KERN_WARNING "%s: skb too small\n", __func__);436		return -EINVAL;437	}438	if (skb->len > ch->maxlen) {439		printk(KERN_WARNING "%s: skb too large(%d/%d)\n",440		       __func__, skb->len, ch->maxlen);441		return -EINVAL;442	}443	/* HW lock must be obtained */444	/* check for pending next_skb */445	if (ch->next_skb) {446		printk(KERN_WARNING447		       "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",448		       __func__, skb->len, ch->next_skb->len);449		return -EBUSY;450	}451	if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {452		test_and_set_bit(FLG_TX_NEXT, &ch->Flags);453		ch->next_skb = skb;454		return 0;455	} else {456		/* write to fifo */457		ch->tx_skb = skb;458		ch->tx_idx = 0;459		confirm_Bsend(ch);460		return 1;461	}462}463EXPORT_SYMBOL(bchannel_senddata);464 465/* The function allocates a new receive skb on demand with a size for the466 * requirements of the current protocol. It returns the tailroom of the467 * receive skb or an error.468 */469int470bchannel_get_rxbuf(struct bchannel *bch, int reqlen)471{472	int len;473 474	if (bch->rx_skb) {475		len = skb_tailroom(bch->rx_skb);476		if (len < reqlen) {477			pr_warn("B%d no space for %d (only %d) bytes\n",478				bch->nr, reqlen, len);479			if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {480				/* send what we have now and try a new buffer */481				recv_Bchannel(bch, 0, true);482			} else {483				/* on HDLC we have to drop too big frames */484				return -EMSGSIZE;485			}486		} else {487			return len;488		}489	}490	/* update current min/max length first */491	if (unlikely(bch->maxlen != bch->next_maxlen))492		bch->maxlen = bch->next_maxlen;493	if (unlikely(bch->minlen != bch->next_minlen))494		bch->minlen = bch->next_minlen;495	if (unlikely(reqlen > bch->maxlen))496		return -EMSGSIZE;497	if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {498		if (reqlen >= bch->minlen) {499			len = reqlen;500		} else {501			len = 2 * bch->minlen;502			if (len > bch->maxlen)503				len = bch->maxlen;504		}505	} else {506		/* with HDLC we do not know the length yet */507		len = bch->maxlen;508	}509	bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC);510	if (!bch->rx_skb) {511		pr_warn("B%d receive no memory for %d bytes\n", bch->nr, len);512		len = -ENOMEM;513	}514	return len;515}516EXPORT_SYMBOL(bchannel_get_rxbuf);517