aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuss Gorby <russ.gorby@intel.com>2011-06-16 17:20:12 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-07-01 18:34:45 -0400
commitbcd5abe28f40cc6a935d3339cde27976f6be3f1a (patch)
tree0bea49f153d4657433524dd5873e19609a83c525
parentd50f6dcaf22a3234a65ae4f6087173e66b7fff56 (diff)
tty: n_gsm: Add raw-ip support
This patch adds the ability to open a network data connection over a mux virtual tty channel. This is for modems that support data connections with raw IP frames instead of PPP. On high speed data connections this eliminates a significant amount of PPP overhead. To use this interface, the application must first tell the modem to open a network connection on a virtual tty. Once that has been accomplished, the app will issue an IOCTL on that virtual tty to create the network interface. The IOCTL will return the index of the interface created. The two IOCTL commands are: ioctl( fd, GSMIOC_ENABLE_NET ); ioctl( fd, GSMIOC_DISABLE_NET ); Signed-off-by: Russ Gorby <russ.gorby@intel.com> Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/tty/n_gsm.c279
-rw-r--r--include/linux/gsmmux.h11
2 files changed, 281 insertions, 9 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index b288ff6cb812..9a13e510daea 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -58,6 +58,10 @@
58#include <linux/serial.h> 58#include <linux/serial.h>
59#include <linux/kfifo.h> 59#include <linux/kfifo.h>
60#include <linux/skbuff.h> 60#include <linux/skbuff.h>
61#include <net/arp.h>
62#include <linux/ip.h>
63#include <linux/netdevice.h>
64#include <linux/etherdevice.h>
61#include <linux/gsmmux.h> 65#include <linux/gsmmux.h>
62 66
63static int debug; 67static int debug;
@@ -77,8 +81,24 @@ module_param(debug, int, 0600);
77 * Semi-arbitrary buffer size limits. 0710 is normally run with 32-64 byte 81 * Semi-arbitrary buffer size limits. 0710 is normally run with 32-64 byte
78 * limits so this is plenty 82 * limits so this is plenty
79 */ 83 */
80#define MAX_MRU 512 84#define MAX_MRU 1500
81#define MAX_MTU 512 85#define MAX_MTU 1500
86#define GSM_NET_TX_TIMEOUT (HZ*10)
87
88/**
89 * struct gsm_mux_net - network interface
90 * @struct gsm_dlci* dlci
91 * @struct net_device_stats stats;
92 *
93 * Created when net interface is initialized.
94 **/
95struct gsm_mux_net {
96 struct kref ref;
97 struct gsm_dlci *dlci;
98 struct net_device_stats stats;
99};
100
101#define STATS(net) (((struct gsm_mux_net *)netdev_priv(net))->stats)
82 102
83/* 103/*
84 * Each block of data we have queued to go out is in the form of 104 * Each block of data we have queued to go out is in the form of
@@ -113,6 +133,7 @@ struct gsm_dlci {
113#define DLCI_OPENING 1 /* Sending SABM not seen UA */ 133#define DLCI_OPENING 1 /* Sending SABM not seen UA */
114#define DLCI_OPEN 2 /* SABM/UA complete */ 134#define DLCI_OPEN 2 /* SABM/UA complete */
115#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */ 135#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */
136 struct mutex mutex;
116 137
117 /* Link layer */ 138 /* Link layer */
118 spinlock_t lock; /* Protects the internal state */ 139 spinlock_t lock; /* Protects the internal state */
@@ -123,6 +144,7 @@ struct gsm_dlci {
123 struct kfifo *fifo; /* Queue fifo for the DLCI */ 144 struct kfifo *fifo; /* Queue fifo for the DLCI */
124 struct kfifo _fifo; /* For new fifo API porting only */ 145 struct kfifo _fifo; /* For new fifo API porting only */
125 int adaption; /* Adaption layer in use */ 146 int adaption; /* Adaption layer in use */
147 int prev_adaption;
126 u32 modem_rx; /* Our incoming virtual modem lines */ 148 u32 modem_rx; /* Our incoming virtual modem lines */
127 u32 modem_tx; /* Our outgoing modem lines */ 149 u32 modem_tx; /* Our outgoing modem lines */
128 int dead; /* Refuse re-open */ 150 int dead; /* Refuse re-open */
@@ -134,6 +156,8 @@ struct gsm_dlci {
134 struct sk_buff_head skb_list; /* Queued frames */ 156 struct sk_buff_head skb_list; /* Queued frames */
135 /* Data handling callback */ 157 /* Data handling callback */
136 void (*data)(struct gsm_dlci *dlci, u8 *data, int len); 158 void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
159 void (*prev_data)(struct gsm_dlci *dlci, u8 *data, int len);
160 struct net_device *net; /* network interface, if created */
137}; 161};
138 162
139/* DLCI 0, 62/63 are special or reseved see gsmtty_open */ 163/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
@@ -880,8 +904,10 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
880 } 904 }
881 memcpy(dp, skb_pull(dlci->skb, len), len); 905 memcpy(dp, skb_pull(dlci->skb, len), len);
882 __gsm_data_queue(dlci, msg); 906 __gsm_data_queue(dlci, msg);
883 if (last) 907 if (last) {
908 kfree_skb(dlci->skb);
884 dlci->skb = NULL; 909 dlci->skb = NULL;
910 }
885 return size; 911 return size;
886} 912}
887 913
@@ -914,7 +940,7 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
914 i++; 940 i++;
915 continue; 941 continue;
916 } 942 }
917 if (dlci->adaption < 3) 943 if (dlci->adaption < 3 && !dlci->net)
918 len = gsm_dlci_data_output(gsm, dlci); 944 len = gsm_dlci_data_output(gsm, dlci);
919 else 945 else
920 len = gsm_dlci_data_output_framed(gsm, dlci); 946 len = gsm_dlci_data_output_framed(gsm, dlci);
@@ -941,9 +967,12 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
941 967
942 spin_lock_irqsave(&dlci->gsm->tx_lock, flags); 968 spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
943 /* If we have nothing running then we need to fire up */ 969 /* If we have nothing running then we need to fire up */
944 if (dlci->gsm->tx_bytes == 0) 970 if (dlci->gsm->tx_bytes == 0) {
945 gsm_dlci_data_output(dlci->gsm, dlci); 971 if (dlci->net)
946 else if (dlci->gsm->tx_bytes < TX_THRESH_LO) 972 gsm_dlci_data_output_framed(dlci->gsm, dlci);
973 else
974 gsm_dlci_data_output(dlci->gsm, dlci);
975 } else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
947 gsm_dlci_data_sweep(dlci->gsm); 976 gsm_dlci_data_sweep(dlci->gsm);
948 spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags); 977 spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
949} 978}
@@ -1577,6 +1606,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
1577 if (dlci == NULL) 1606 if (dlci == NULL)
1578 return NULL; 1607 return NULL;
1579 spin_lock_init(&dlci->lock); 1608 spin_lock_init(&dlci->lock);
1609 mutex_init(&dlci->mutex);
1580 dlci->fifo = &dlci->_fifo; 1610 dlci->fifo = &dlci->_fifo;
1581 if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { 1611 if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
1582 kfree(dlci); 1612 kfree(dlci);
@@ -2059,7 +2089,6 @@ struct gsm_mux *gsm_alloc_mux(void)
2059 gsm->t2 = T2; 2089 gsm->t2 = T2;
2060 gsm->n2 = N2; 2090 gsm->n2 = N2;
2061 gsm->ftype = UIH; 2091 gsm->ftype = UIH;
2062 gsm->initiator = 0;
2063 gsm->adaption = 1; 2092 gsm->adaption = 1;
2064 gsm->encoding = 1; 2093 gsm->encoding = 1;
2065 gsm->mru = 64; /* Default to encoding 1 so these should be 64 */ 2094 gsm->mru = 64; /* Default to encoding 1 so these should be 64 */
@@ -2478,6 +2507,210 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
2478 } 2507 }
2479} 2508}
2480 2509
2510/*
2511 * Network interface
2512 *
2513 */
2514
2515static int gsm_mux_net_open(struct net_device *net)
2516{
2517 pr_debug("%s called\n", __func__);
2518 netif_start_queue(net);
2519 return 0;
2520}
2521
2522static int gsm_mux_net_close(struct net_device *net)
2523{
2524 netif_stop_queue(net);
2525 return 0;
2526}
2527
2528static struct net_device_stats *gsm_mux_net_get_stats(struct net_device *net)
2529{
2530 return &((struct gsm_mux_net *)netdev_priv(net))->stats;
2531}
2532static void dlci_net_free(struct gsm_dlci *dlci)
2533{
2534 if (!dlci->net) {
2535 WARN_ON(1);
2536 return;
2537 }
2538 dlci->adaption = dlci->prev_adaption;
2539 dlci->data = dlci->prev_data;
2540 free_netdev(dlci->net);
2541 dlci->net = NULL;
2542}
2543static void net_free(struct kref *ref)
2544{
2545 struct gsm_mux_net *mux_net;
2546 struct gsm_dlci *dlci;
2547
2548 mux_net = container_of(ref, struct gsm_mux_net, ref);
2549 dlci = mux_net->dlci;
2550
2551 if (dlci->net) {
2552 unregister_netdev(dlci->net);
2553 dlci_net_free(dlci);
2554 }
2555}
2556
2557static int gsm_mux_net_start_xmit(struct sk_buff *skb,
2558 struct net_device *net)
2559{
2560 struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
2561 struct gsm_dlci *dlci = mux_net->dlci;
2562 kref_get(&mux_net->ref);
2563
2564 skb_queue_head(&dlci->skb_list, skb);
2565 STATS(net).tx_packets++;
2566 STATS(net).tx_bytes += skb->len;
2567 gsm_dlci_data_kick(dlci);
2568 /* And tell the kernel when the last transmit started. */
2569 net->trans_start = jiffies;
2570 kref_put(&mux_net->ref, net_free);
2571 return NETDEV_TX_OK;
2572}
2573
2574/* called when a packet did not ack after watchdogtimeout */
2575static void gsm_mux_net_tx_timeout(struct net_device *net)
2576{
2577 /* Tell syslog we are hosed. */
2578 dev_dbg(&net->dev, "Tx timed out.\n");
2579
2580 /* Update statistics */
2581 STATS(net).tx_errors++;
2582}
2583
2584static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
2585 unsigned char *in_buf, int size)
2586{
2587 struct net_device *net = dlci->net;
2588 struct sk_buff *skb;
2589 struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
2590 kref_get(&mux_net->ref);
2591
2592 /* Allocate an sk_buff */
2593 skb = dev_alloc_skb(size + NET_IP_ALIGN);
2594 if (!skb) {
2595 /* We got no receive buffer. */
2596 STATS(net).rx_dropped++;
2597 kref_put(&mux_net->ref, net_free);
2598 return;
2599 }
2600 skb_reserve(skb, NET_IP_ALIGN);
2601 memcpy(skb_put(skb, size), in_buf, size);
2602
2603 skb->dev = net;
2604 skb->protocol = __constant_htons(ETH_P_IP);
2605
2606 /* Ship it off to the kernel */
2607 netif_rx(skb);
2608
2609 /* update out statistics */
2610 STATS(net).rx_packets++;
2611 STATS(net).rx_bytes += size;
2612 kref_put(&mux_net->ref, net_free);
2613 return;
2614}
2615
2616int gsm_change_mtu(struct net_device *net, int new_mtu)
2617{
2618 struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
2619 if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu))
2620 return -EINVAL;
2621 net->mtu = new_mtu;
2622 return 0;
2623}
2624
2625static void gsm_mux_net_init(struct net_device *net)
2626{
2627 static const struct net_device_ops gsm_netdev_ops = {
2628 .ndo_open = gsm_mux_net_open,
2629 .ndo_stop = gsm_mux_net_close,
2630 .ndo_start_xmit = gsm_mux_net_start_xmit,
2631 .ndo_tx_timeout = gsm_mux_net_tx_timeout,
2632 .ndo_get_stats = gsm_mux_net_get_stats,
2633 .ndo_change_mtu = gsm_change_mtu,
2634 };
2635
2636 net->netdev_ops = &gsm_netdev_ops;
2637
2638 /* fill in the other fields */
2639 net->watchdog_timeo = GSM_NET_TX_TIMEOUT;
2640 net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
2641 net->type = ARPHRD_NONE;
2642 net->tx_queue_len = 10;
2643}
2644
2645
2646/* caller holds the dlci mutex */
2647static void gsm_destroy_network(struct gsm_dlci *dlci)
2648{
2649 struct gsm_mux_net *mux_net;
2650
2651 pr_debug("destroy network interface");
2652 if (!dlci->net)
2653 return;
2654 mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net);
2655 kref_put(&mux_net->ref, net_free);
2656}
2657
2658
2659/* caller holds the dlci mutex */
2660static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
2661{
2662 char *netname;
2663 int retval = 0;
2664 struct net_device *net;
2665 struct gsm_mux_net *mux_net;
2666
2667 if (!capable(CAP_NET_ADMIN))
2668 return -EPERM;
2669
2670 /* Already in a non tty mode */
2671 if (dlci->adaption > 2)
2672 return -EBUSY;
2673
2674 if (nc->protocol != htons(ETH_P_IP))
2675 return -EPROTONOSUPPORT;
2676
2677 if (nc->adaption != 3 && nc->adaption != 4)
2678 return -EPROTONOSUPPORT;
2679
2680 pr_debug("create network interface");
2681
2682 netname = "gsm%d";
2683 if (nc->if_name[0] != '\0')
2684 netname = nc->if_name;
2685 net = alloc_netdev(sizeof(struct gsm_mux_net),
2686 netname,
2687 gsm_mux_net_init);
2688 if (!net) {
2689 pr_err("alloc_netdev failed");
2690 return -ENOMEM;
2691 }
2692 net->mtu = dlci->gsm->mtu;
2693 mux_net = (struct gsm_mux_net *)netdev_priv(net);
2694 mux_net->dlci = dlci;
2695 kref_init(&mux_net->ref);
2696 strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */
2697
2698 /* reconfigure dlci for network */
2699 dlci->prev_adaption = dlci->adaption;
2700 dlci->prev_data = dlci->data;
2701 dlci->adaption = nc->adaption;
2702 dlci->data = gsm_mux_rx_netchar;
2703 dlci->net = net;
2704
2705 pr_debug("register netdev");
2706 retval = register_netdev(net);
2707 if (retval) {
2708 pr_err("network register fail %d\n", retval);
2709 dlci_net_free(dlci);
2710 return retval;
2711 }
2712 return net->ifindex; /* return network index */
2713}
2481 2714
2482/* Line discipline for real tty */ 2715/* Line discipline for real tty */
2483struct tty_ldisc_ops tty_ldisc_packet = { 2716struct tty_ldisc_ops tty_ldisc_packet = {
@@ -2598,6 +2831,9 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
2598 struct gsm_dlci *dlci = tty->driver_data; 2831 struct gsm_dlci *dlci = tty->driver_data;
2599 if (dlci == NULL) 2832 if (dlci == NULL)
2600 return; 2833 return;
2834 mutex_lock(&dlci->mutex);
2835 gsm_destroy_network(dlci);
2836 mutex_unlock(&dlci->mutex);
2601 if (tty_port_close_start(&dlci->port, tty, filp) == 0) 2837 if (tty_port_close_start(&dlci->port, tty, filp) == 0)
2602 return; 2838 return;
2603 gsm_dlci_begin_close(dlci); 2839 gsm_dlci_begin_close(dlci);
@@ -2679,7 +2915,32 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
2679static int gsmtty_ioctl(struct tty_struct *tty, 2915static int gsmtty_ioctl(struct tty_struct *tty,
2680 unsigned int cmd, unsigned long arg) 2916 unsigned int cmd, unsigned long arg)
2681{ 2917{
2682 return -ENOIOCTLCMD; 2918 struct gsm_dlci *dlci = tty->driver_data;
2919 struct gsm_netconfig nc;
2920 int index;
2921
2922 switch (cmd) {
2923 case GSMIOC_ENABLE_NET:
2924 if (copy_from_user(&nc, (void __user *)arg, sizeof(nc)))
2925 return -EFAULT;
2926 nc.if_name[IFNAMSIZ-1] = '\0';
2927 /* return net interface index or error code */
2928 mutex_lock(&dlci->mutex);
2929 index = gsm_create_network(dlci, &nc);
2930 mutex_unlock(&dlci->mutex);
2931 if (copy_to_user((void __user *)arg, &nc, sizeof(nc)))
2932 return -EFAULT;
2933 return index;
2934 case GSMIOC_DISABLE_NET:
2935 if (!capable(CAP_NET_ADMIN))
2936 return -EPERM;
2937 mutex_lock(&dlci->mutex);
2938 gsm_destroy_network(dlci);
2939 mutex_unlock(&dlci->mutex);
2940 return 0;
2941 default:
2942 return -ENOIOCTLCMD;
2943 }
2683} 2944}
2684 2945
2685static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old) 2946static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
diff --git a/include/linux/gsmmux.h b/include/linux/gsmmux.h
index 378de4195caf..c25e9477f7c3 100644
--- a/include/linux/gsmmux.h
+++ b/include/linux/gsmmux.h
@@ -21,5 +21,16 @@ struct gsm_config
21#define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config) 21#define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config)
22#define GSMIOC_SETCONF _IOW('G', 1, struct gsm_config) 22#define GSMIOC_SETCONF _IOW('G', 1, struct gsm_config)
23 23
24struct gsm_netconfig {
25 unsigned int adaption; /* Adaption to use in network mode */
26 unsigned short protocol;/* Protocol to use - only ETH_P_IP supported */
27 unsigned short unused2;
28 char if_name[IFNAMSIZ]; /* interface name format string */
29 __u8 unused[28]; /* For future use */
30};
31
32#define GSMIOC_ENABLE_NET _IOW('G', 2, struct gsm_netconfig)
33#define GSMIOC_DISABLE_NET _IO('G', 3)
34
24 35
25#endif 36#endif