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