brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · fe569f6 Raw
518 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * IPWireless 3G PCMCIA Network Driver4 *5 * Original code6 *   by Stephen Blackheath <stephen@blacksapphire.com>,7 *      Ben Martel <benm@symmetric.co.nz>8 *9 * Copyrighted as follows:10 *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)11 *12 * Various driver changes and rewrites, port to new kernels13 *   Copyright (C) 2006-2007 Jiri Kosina14 *15 * Misc code cleanups and updates16 *   Copyright (C) 2007 David Sterba17 */18 19#include <linux/interrupt.h>20#include <linux/kernel.h>21#include <linux/mutex.h>22#include <linux/netdevice.h>23#include <linux/ppp_channel.h>24#include <linux/ppp_defs.h>25#include <linux/slab.h>26#include <linux/ppp-ioctl.h>27#include <linux/skbuff.h>28 29#include "network.h"30#include "hardware.h"31#include "main.h"32#include "tty.h"33 34#define MAX_ASSOCIATED_TTYS 235 36#define SC_RCV_BITS     (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)37 38struct ipw_network {39	/* Hardware context, used for calls to hardware layer. */40	struct ipw_hardware *hardware;41	/* Context for kernel 'generic_ppp' functionality */42	struct ppp_channel *ppp_channel;43	/* tty context connected with IPW console */44	struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS];45	/* True if ppp needs waking up once we're ready to xmit */46	int ppp_blocked;47	/* Number of packets queued up in hardware module. */48	int outgoing_packets_queued;49	/* Spinlock to avoid interrupts during shutdown */50	spinlock_t lock;51	struct mutex close_lock;52 53	/* PPP ioctl data, not actually used anywere */54	unsigned int flags;55	unsigned int rbits;56	u32 xaccm[8];57	u32 raccm;58	int mru;59 60	int shutting_down;61	unsigned int ras_control_lines;62 63	struct work_struct work_go_online;64	struct work_struct work_go_offline;65};66 67static void notify_packet_sent(void *callback_data, unsigned int packet_length)68{69	struct ipw_network *network = callback_data;70	unsigned long flags;71 72	spin_lock_irqsave(&network->lock, flags);73	network->outgoing_packets_queued--;74	if (network->ppp_channel != NULL) {75		if (network->ppp_blocked) {76			network->ppp_blocked = 0;77			spin_unlock_irqrestore(&network->lock, flags);78			ppp_output_wakeup(network->ppp_channel);79			if (ipwireless_debug)80				printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME81				       ": ppp unblocked\n");82		} else83			spin_unlock_irqrestore(&network->lock, flags);84	} else85		spin_unlock_irqrestore(&network->lock, flags);86}87 88/*89 * Called by the ppp system when it has a packet to send to the hardware.90 */91static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,92				     struct sk_buff *skb)93{94	struct ipw_network *network = ppp_channel->private;95	unsigned long flags;96 97	spin_lock_irqsave(&network->lock, flags);98	if (network->outgoing_packets_queued < ipwireless_out_queue) {99		unsigned char *buf;100		static unsigned char header[] = {101			PPP_ALLSTATIONS, /* 0xff */102			PPP_UI,		 /* 0x03 */103		};104		int ret;105 106		network->outgoing_packets_queued++;107		spin_unlock_irqrestore(&network->lock, flags);108 109		/*110		 * If we have the requested amount of headroom in the skb we111		 * were handed, then we can add the header efficiently.112		 */113		if (skb_headroom(skb) >= 2) {114			memcpy(skb_push(skb, 2), header, 2);115			ret = ipwireless_send_packet(network->hardware,116					       IPW_CHANNEL_RAS, skb->data,117					       skb->len,118					       notify_packet_sent,119					       network);120			if (ret < 0) {121				skb_pull(skb, 2);122				return 0;123			}124		} else {125			/* Otherwise (rarely) we do it inefficiently. */126			buf = kmalloc(skb->len + 2, GFP_ATOMIC);127			if (!buf)128				return 0;129			memcpy(buf + 2, skb->data, skb->len);130			memcpy(buf, header, 2);131			ret = ipwireless_send_packet(network->hardware,132					       IPW_CHANNEL_RAS, buf,133					       skb->len + 2,134					       notify_packet_sent,135					       network);136			kfree(buf);137			if (ret < 0)138				return 0;139		}140		kfree_skb(skb);141		return 1;142	} else {143		/*144		 * Otherwise reject the packet, and flag that the ppp system145		 * needs to be unblocked once we are ready to send.146		 */147		network->ppp_blocked = 1;148		spin_unlock_irqrestore(&network->lock, flags);149		if (ipwireless_debug)150			printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": ppp blocked\n");151		return 0;152	}153}154 155/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */156static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel,157				unsigned int cmd, unsigned long arg)158{159	struct ipw_network *network = ppp_channel->private;160	int err, val;161	u32 accm[8];162	int __user *user_arg = (int __user *) arg;163 164	err = -EFAULT;165	switch (cmd) {166	case PPPIOCGFLAGS:167		val = network->flags | network->rbits;168		if (put_user(val, user_arg))169			break;170		err = 0;171		break;172 173	case PPPIOCSFLAGS:174		if (get_user(val, user_arg))175			break;176		network->flags = val & ~SC_RCV_BITS;177		network->rbits = val & SC_RCV_BITS;178		err = 0;179		break;180 181	case PPPIOCGASYNCMAP:182		if (put_user(network->xaccm[0], user_arg))183			break;184		err = 0;185		break;186 187	case PPPIOCSASYNCMAP:188		if (get_user(network->xaccm[0], user_arg))189			break;190		err = 0;191		break;192 193	case PPPIOCGRASYNCMAP:194		if (put_user(network->raccm, user_arg))195			break;196		err = 0;197		break;198 199	case PPPIOCSRASYNCMAP:200		if (get_user(network->raccm, user_arg))201			break;202		err = 0;203		break;204 205	case PPPIOCGXASYNCMAP:206		if (copy_to_user((void __user *) arg, network->xaccm,207					sizeof(network->xaccm)))208			break;209		err = 0;210		break;211 212	case PPPIOCSXASYNCMAP:213		if (copy_from_user(accm, (void __user *) arg, sizeof(accm)))214			break;215		accm[2] &= ~0x40000000U;	/* can't escape 0x5e */216		accm[3] |= 0x60000000U;	/* must escape 0x7d, 0x7e */217		memcpy(network->xaccm, accm, sizeof(network->xaccm));218		err = 0;219		break;220 221	case PPPIOCGMRU:222		if (put_user(network->mru, user_arg))223			break;224		err = 0;225		break;226 227	case PPPIOCSMRU:228		if (get_user(val, user_arg))229			break;230		if (val < PPP_MRU)231			val = PPP_MRU;232		network->mru = val;233		err = 0;234		break;235 236	default:237		err = -ENOTTY;238	}239 240	return err;241}242 243static const struct ppp_channel_ops ipwireless_ppp_channel_ops = {244	.start_xmit = ipwireless_ppp_start_xmit,245	.ioctl      = ipwireless_ppp_ioctl246};247 248static void do_go_online(struct work_struct *work_go_online)249{250	struct ipw_network *network =251		container_of(work_go_online, struct ipw_network,252				work_go_online);253	unsigned long flags;254 255	spin_lock_irqsave(&network->lock, flags);256	if (!network->ppp_channel) {257		struct ppp_channel *channel;258 259		spin_unlock_irqrestore(&network->lock, flags);260		channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL);261		if (!channel) {262			printk(KERN_ERR IPWIRELESS_PCCARD_NAME263					": unable to allocate PPP channel\n");264			return;265		}266		channel->private = network;267		channel->mtu = 16384;	/* Wild guess */268		channel->hdrlen = 2;269		channel->ops = &ipwireless_ppp_channel_ops;270 271		network->flags = 0;272		network->rbits = 0;273		network->mru = PPP_MRU;274		memset(network->xaccm, 0, sizeof(network->xaccm));275		network->xaccm[0] = ~0U;276		network->xaccm[3] = 0x60000000U;277		network->raccm = ~0U;278		if (ppp_register_channel(channel) < 0) {279			printk(KERN_ERR IPWIRELESS_PCCARD_NAME280					": unable to register PPP channel\n");281			kfree(channel);282			return;283		}284		spin_lock_irqsave(&network->lock, flags);285		network->ppp_channel = channel;286	}287	spin_unlock_irqrestore(&network->lock, flags);288}289 290static void do_go_offline(struct work_struct *work_go_offline)291{292	struct ipw_network *network =293		container_of(work_go_offline, struct ipw_network,294				work_go_offline);295	unsigned long flags;296 297	mutex_lock(&network->close_lock);298	spin_lock_irqsave(&network->lock, flags);299	if (network->ppp_channel != NULL) {300		struct ppp_channel *channel = network->ppp_channel;301 302		network->ppp_channel = NULL;303		spin_unlock_irqrestore(&network->lock, flags);304		mutex_unlock(&network->close_lock);305		ppp_unregister_channel(channel);306	} else {307		spin_unlock_irqrestore(&network->lock, flags);308		mutex_unlock(&network->close_lock);309	}310}311 312void ipwireless_network_notify_control_line_change(struct ipw_network *network,313						   unsigned int channel_idx,314						   unsigned int control_lines,315						   unsigned int changed_mask)316{317	int i;318 319	if (channel_idx == IPW_CHANNEL_RAS)320		network->ras_control_lines = control_lines;321 322	for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {323		struct ipw_tty *tty =324			network->associated_ttys[channel_idx][i];325 326		/*327		 * If it's associated with a tty (other than the RAS channel328		 * when we're online), then send the data to that tty.  The RAS329		 * channel's data is handled above - it always goes through330		 * ppp_generic.331		 */332		if (tty)333			ipwireless_tty_notify_control_line_change(tty,334								  channel_idx,335								  control_lines,336								  changed_mask);337	}338}339 340/*341 * Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI)342 * bytes, which are required on sent packet, but not always present on received343 * packets344 */345static struct sk_buff *ipw_packet_received_skb(unsigned char *data,346					       unsigned int length)347{348	struct sk_buff *skb;349 350	if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) {351		length -= 2;352		data += 2;353	}354 355	skb = dev_alloc_skb(length + 4);356	if (skb == NULL)357		return NULL;358	skb_reserve(skb, 2);359	skb_put_data(skb, data, length);360 361	return skb;362}363 364void ipwireless_network_packet_received(struct ipw_network *network,365					unsigned int channel_idx,366					unsigned char *data,367					unsigned int length)368{369	int i;370	unsigned long flags;371 372	for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {373		struct ipw_tty *tty = network->associated_ttys[channel_idx][i];374 375		if (!tty)376			continue;377 378		/*379		 * If it's associated with a tty (other than the RAS channel380		 * when we're online), then send the data to that tty.  The RAS381		 * channel's data is handled above - it always goes through382		 * ppp_generic.383		 */384		if (channel_idx == IPW_CHANNEL_RAS385				&& (network->ras_control_lines &386					IPW_CONTROL_LINE_DCD) != 0387				&& ipwireless_tty_is_modem(tty)) {388			/*389			 * If data came in on the RAS channel and this tty is390			 * the modem tty, and we are online, then we send it to391			 * the PPP layer.392			 */393			mutex_lock(&network->close_lock);394			spin_lock_irqsave(&network->lock, flags);395			if (network->ppp_channel != NULL) {396				struct sk_buff *skb;397 398				spin_unlock_irqrestore(&network->lock,399						flags);400 401				/* Send the data to the ppp_generic module. */402				skb = ipw_packet_received_skb(data, length);403				if (skb)404					ppp_input(network->ppp_channel, skb);405			} else406				spin_unlock_irqrestore(&network->lock,407						flags);408			mutex_unlock(&network->close_lock);409		}410		/* Otherwise we send it out the tty. */411		else412			ipwireless_tty_received(tty, data, length);413	}414}415 416struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw)417{418	struct ipw_network *network =419		kzalloc(sizeof(struct ipw_network), GFP_KERNEL);420 421	if (!network)422		return NULL;423 424	spin_lock_init(&network->lock);425	mutex_init(&network->close_lock);426 427	network->hardware = hw;428 429	INIT_WORK(&network->work_go_online, do_go_online);430	INIT_WORK(&network->work_go_offline, do_go_offline);431 432	ipwireless_associate_network(hw, network);433 434	return network;435}436 437void ipwireless_network_free(struct ipw_network *network)438{439	network->shutting_down = 1;440 441	ipwireless_ppp_close(network);442	flush_work(&network->work_go_online);443	flush_work(&network->work_go_offline);444 445	ipwireless_stop_interrupts(network->hardware);446	ipwireless_associate_network(network->hardware, NULL);447 448	kfree(network);449}450 451void ipwireless_associate_network_tty(struct ipw_network *network,452				      unsigned int channel_idx,453				      struct ipw_tty *tty)454{455	int i;456 457	for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)458		if (network->associated_ttys[channel_idx][i] == NULL) {459			network->associated_ttys[channel_idx][i] = tty;460			break;461		}462}463 464void ipwireless_disassociate_network_ttys(struct ipw_network *network,465					  unsigned int channel_idx)466{467	int i;468 469	for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)470		network->associated_ttys[channel_idx][i] = NULL;471}472 473void ipwireless_ppp_open(struct ipw_network *network)474{475	if (ipwireless_debug)476		printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n");477	schedule_work(&network->work_go_online);478}479 480void ipwireless_ppp_close(struct ipw_network *network)481{482	/* Disconnect from the wireless network. */483	if (ipwireless_debug)484		printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n");485	schedule_work(&network->work_go_offline);486}487 488int ipwireless_ppp_channel_index(struct ipw_network *network)489{490	int ret = -1;491	unsigned long flags;492 493	spin_lock_irqsave(&network->lock, flags);494	if (network->ppp_channel != NULL)495		ret = ppp_channel_index(network->ppp_channel);496	spin_unlock_irqrestore(&network->lock, flags);497 498	return ret;499}500 501int ipwireless_ppp_unit_number(struct ipw_network *network)502{503	int ret = -1;504	unsigned long flags;505 506	spin_lock_irqsave(&network->lock, flags);507	if (network->ppp_channel != NULL)508		ret = ppp_unit_number(network->ppp_channel);509	spin_unlock_irqrestore(&network->lock, flags);510 511	return ret;512}513 514int ipwireless_ppp_mru(const struct ipw_network *network)515{516	return network->mru;517}518