Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Russ Gorby and committed by
Greg Kroah-Hartman
bcd5abe2 d50f6dca

+281 -9
+270 -9
drivers/tty/n_gsm.c
··· 58 58 #include <linux/serial.h> 59 59 #include <linux/kfifo.h> 60 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 65 #include <linux/gsmmux.h> 62 66 63 67 static int debug; ··· 81 77 * Semi-arbitrary buffer size limits. 0710 is normally run with 32-64 byte 82 78 * limits so this is plenty 83 79 */ 84 - #define MAX_MRU 512 85 - #define MAX_MTU 512 80 + #define MAX_MRU 1500 81 + #define MAX_MTU 1500 82 + #define GSM_NET_TX_TIMEOUT (HZ*10) 83 + 84 + /** 85 + * struct gsm_mux_net - network interface 86 + * @struct gsm_dlci* dlci 87 + * @struct net_device_stats stats; 88 + * 89 + * Created when net interface is initialized. 90 + **/ 91 + struct gsm_mux_net { 92 + struct kref ref; 93 + struct gsm_dlci *dlci; 94 + struct net_device_stats stats; 95 + }; 96 + 97 + #define STATS(net) (((struct gsm_mux_net *)netdev_priv(net))->stats) 86 98 87 99 /* 88 100 * Each block of data we have queued to go out is in the form of ··· 133 113 #define DLCI_OPENING 1 /* Sending SABM not seen UA */ 134 114 #define DLCI_OPEN 2 /* SABM/UA complete */ 135 115 #define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */ 116 + struct mutex mutex; 136 117 137 118 /* Link layer */ 138 119 spinlock_t lock; /* Protects the internal state */ ··· 144 123 struct kfifo *fifo; /* Queue fifo for the DLCI */ 145 124 struct kfifo _fifo; /* For new fifo API porting only */ 146 125 int adaption; /* Adaption layer in use */ 126 + int prev_adaption; 147 127 u32 modem_rx; /* Our incoming virtual modem lines */ 148 128 u32 modem_tx; /* Our outgoing modem lines */ 149 129 int dead; /* Refuse re-open */ ··· 156 134 struct sk_buff_head skb_list; /* Queued frames */ 157 135 /* Data handling callback */ 158 136 void (*data)(struct gsm_dlci *dlci, u8 *data, int len); 137 + void (*prev_data)(struct gsm_dlci *dlci, u8 *data, int len); 138 + struct net_device *net; /* network interface, if created */ 159 139 }; 160 140 161 141 /* DLCI 0, 62/63 are special or reseved see gsmtty_open */ ··· 904 880 } 905 881 memcpy(dp, skb_pull(dlci->skb, len), len); 906 882 __gsm_data_queue(dlci, msg); 907 - if (last) 883 + if (last) { 884 + kfree_skb(dlci->skb); 908 885 dlci->skb = NULL; 886 + } 909 887 return size; 910 888 } 911 889 ··· 940 914 i++; 941 915 continue; 942 916 } 943 - if (dlci->adaption < 3) 917 + if (dlci->adaption < 3 && !dlci->net) 944 918 len = gsm_dlci_data_output(gsm, dlci); 945 919 else 946 920 len = gsm_dlci_data_output_framed(gsm, dlci); ··· 967 941 968 942 spin_lock_irqsave(&dlci->gsm->tx_lock, flags); 969 943 /* If we have nothing running then we need to fire up */ 970 - if (dlci->gsm->tx_bytes == 0) 971 - gsm_dlci_data_output(dlci->gsm, dlci); 972 - else if (dlci->gsm->tx_bytes < TX_THRESH_LO) 944 + if (dlci->gsm->tx_bytes == 0) { 945 + if (dlci->net) 946 + gsm_dlci_data_output_framed(dlci->gsm, dlci); 947 + else 948 + gsm_dlci_data_output(dlci->gsm, dlci); 949 + } else if (dlci->gsm->tx_bytes < TX_THRESH_LO) 973 950 gsm_dlci_data_sweep(dlci->gsm); 974 951 spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags); 975 952 } ··· 1606 1577 if (dlci == NULL) 1607 1578 return NULL; 1608 1579 spin_lock_init(&dlci->lock); 1580 + mutex_init(&dlci->mutex); 1609 1581 dlci->fifo = &dlci->_fifo; 1610 1582 if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { 1611 1583 kfree(dlci); ··· 2089 2059 gsm->t2 = T2; 2090 2060 gsm->n2 = N2; 2091 2061 gsm->ftype = UIH; 2092 - gsm->initiator = 0; 2093 2062 gsm->adaption = 1; 2094 2063 gsm->encoding = 1; 2095 2064 gsm->mru = 64; /* Default to encoding 1 so these should be 64 */ ··· 2507 2478 } 2508 2479 } 2509 2480 2481 + /* 2482 + * Network interface 2483 + * 2484 + */ 2485 + 2486 + static int gsm_mux_net_open(struct net_device *net) 2487 + { 2488 + pr_debug("%s called\n", __func__); 2489 + netif_start_queue(net); 2490 + return 0; 2491 + } 2492 + 2493 + static int gsm_mux_net_close(struct net_device *net) 2494 + { 2495 + netif_stop_queue(net); 2496 + return 0; 2497 + } 2498 + 2499 + static struct net_device_stats *gsm_mux_net_get_stats(struct net_device *net) 2500 + { 2501 + return &((struct gsm_mux_net *)netdev_priv(net))->stats; 2502 + } 2503 + static void dlci_net_free(struct gsm_dlci *dlci) 2504 + { 2505 + if (!dlci->net) { 2506 + WARN_ON(1); 2507 + return; 2508 + } 2509 + dlci->adaption = dlci->prev_adaption; 2510 + dlci->data = dlci->prev_data; 2511 + free_netdev(dlci->net); 2512 + dlci->net = NULL; 2513 + } 2514 + static void net_free(struct kref *ref) 2515 + { 2516 + struct gsm_mux_net *mux_net; 2517 + struct gsm_dlci *dlci; 2518 + 2519 + mux_net = container_of(ref, struct gsm_mux_net, ref); 2520 + dlci = mux_net->dlci; 2521 + 2522 + if (dlci->net) { 2523 + unregister_netdev(dlci->net); 2524 + dlci_net_free(dlci); 2525 + } 2526 + } 2527 + 2528 + static int gsm_mux_net_start_xmit(struct sk_buff *skb, 2529 + struct net_device *net) 2530 + { 2531 + struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); 2532 + struct gsm_dlci *dlci = mux_net->dlci; 2533 + kref_get(&mux_net->ref); 2534 + 2535 + skb_queue_head(&dlci->skb_list, skb); 2536 + STATS(net).tx_packets++; 2537 + STATS(net).tx_bytes += skb->len; 2538 + gsm_dlci_data_kick(dlci); 2539 + /* And tell the kernel when the last transmit started. */ 2540 + net->trans_start = jiffies; 2541 + kref_put(&mux_net->ref, net_free); 2542 + return NETDEV_TX_OK; 2543 + } 2544 + 2545 + /* called when a packet did not ack after watchdogtimeout */ 2546 + static void gsm_mux_net_tx_timeout(struct net_device *net) 2547 + { 2548 + /* Tell syslog we are hosed. */ 2549 + dev_dbg(&net->dev, "Tx timed out.\n"); 2550 + 2551 + /* Update statistics */ 2552 + STATS(net).tx_errors++; 2553 + } 2554 + 2555 + static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, 2556 + unsigned char *in_buf, int size) 2557 + { 2558 + struct net_device *net = dlci->net; 2559 + struct sk_buff *skb; 2560 + struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); 2561 + kref_get(&mux_net->ref); 2562 + 2563 + /* Allocate an sk_buff */ 2564 + skb = dev_alloc_skb(size + NET_IP_ALIGN); 2565 + if (!skb) { 2566 + /* We got no receive buffer. */ 2567 + STATS(net).rx_dropped++; 2568 + kref_put(&mux_net->ref, net_free); 2569 + return; 2570 + } 2571 + skb_reserve(skb, NET_IP_ALIGN); 2572 + memcpy(skb_put(skb, size), in_buf, size); 2573 + 2574 + skb->dev = net; 2575 + skb->protocol = __constant_htons(ETH_P_IP); 2576 + 2577 + /* Ship it off to the kernel */ 2578 + netif_rx(skb); 2579 + 2580 + /* update out statistics */ 2581 + STATS(net).rx_packets++; 2582 + STATS(net).rx_bytes += size; 2583 + kref_put(&mux_net->ref, net_free); 2584 + return; 2585 + } 2586 + 2587 + int gsm_change_mtu(struct net_device *net, int new_mtu) 2588 + { 2589 + struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); 2590 + if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu)) 2591 + return -EINVAL; 2592 + net->mtu = new_mtu; 2593 + return 0; 2594 + } 2595 + 2596 + static void gsm_mux_net_init(struct net_device *net) 2597 + { 2598 + static const struct net_device_ops gsm_netdev_ops = { 2599 + .ndo_open = gsm_mux_net_open, 2600 + .ndo_stop = gsm_mux_net_close, 2601 + .ndo_start_xmit = gsm_mux_net_start_xmit, 2602 + .ndo_tx_timeout = gsm_mux_net_tx_timeout, 2603 + .ndo_get_stats = gsm_mux_net_get_stats, 2604 + .ndo_change_mtu = gsm_change_mtu, 2605 + }; 2606 + 2607 + net->netdev_ops = &gsm_netdev_ops; 2608 + 2609 + /* fill in the other fields */ 2610 + net->watchdog_timeo = GSM_NET_TX_TIMEOUT; 2611 + net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; 2612 + net->type = ARPHRD_NONE; 2613 + net->tx_queue_len = 10; 2614 + } 2615 + 2616 + 2617 + /* caller holds the dlci mutex */ 2618 + static void gsm_destroy_network(struct gsm_dlci *dlci) 2619 + { 2620 + struct gsm_mux_net *mux_net; 2621 + 2622 + pr_debug("destroy network interface"); 2623 + if (!dlci->net) 2624 + return; 2625 + mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); 2626 + kref_put(&mux_net->ref, net_free); 2627 + } 2628 + 2629 + 2630 + /* caller holds the dlci mutex */ 2631 + static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) 2632 + { 2633 + char *netname; 2634 + int retval = 0; 2635 + struct net_device *net; 2636 + struct gsm_mux_net *mux_net; 2637 + 2638 + if (!capable(CAP_NET_ADMIN)) 2639 + return -EPERM; 2640 + 2641 + /* Already in a non tty mode */ 2642 + if (dlci->adaption > 2) 2643 + return -EBUSY; 2644 + 2645 + if (nc->protocol != htons(ETH_P_IP)) 2646 + return -EPROTONOSUPPORT; 2647 + 2648 + if (nc->adaption != 3 && nc->adaption != 4) 2649 + return -EPROTONOSUPPORT; 2650 + 2651 + pr_debug("create network interface"); 2652 + 2653 + netname = "gsm%d"; 2654 + if (nc->if_name[0] != '\0') 2655 + netname = nc->if_name; 2656 + net = alloc_netdev(sizeof(struct gsm_mux_net), 2657 + netname, 2658 + gsm_mux_net_init); 2659 + if (!net) { 2660 + pr_err("alloc_netdev failed"); 2661 + return -ENOMEM; 2662 + } 2663 + net->mtu = dlci->gsm->mtu; 2664 + mux_net = (struct gsm_mux_net *)netdev_priv(net); 2665 + mux_net->dlci = dlci; 2666 + kref_init(&mux_net->ref); 2667 + strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */ 2668 + 2669 + /* reconfigure dlci for network */ 2670 + dlci->prev_adaption = dlci->adaption; 2671 + dlci->prev_data = dlci->data; 2672 + dlci->adaption = nc->adaption; 2673 + dlci->data = gsm_mux_rx_netchar; 2674 + dlci->net = net; 2675 + 2676 + pr_debug("register netdev"); 2677 + retval = register_netdev(net); 2678 + if (retval) { 2679 + pr_err("network register fail %d\n", retval); 2680 + dlci_net_free(dlci); 2681 + return retval; 2682 + } 2683 + return net->ifindex; /* return network index */ 2684 + } 2510 2685 2511 2686 /* Line discipline for real tty */ 2512 2687 struct tty_ldisc_ops tty_ldisc_packet = { ··· 2831 2598 struct gsm_dlci *dlci = tty->driver_data; 2832 2599 if (dlci == NULL) 2833 2600 return; 2601 + mutex_lock(&dlci->mutex); 2602 + gsm_destroy_network(dlci); 2603 + mutex_unlock(&dlci->mutex); 2834 2604 if (tty_port_close_start(&dlci->port, tty, filp) == 0) 2835 2605 return; 2836 2606 gsm_dlci_begin_close(dlci); ··· 2915 2679 static int gsmtty_ioctl(struct tty_struct *tty, 2916 2680 unsigned int cmd, unsigned long arg) 2917 2681 { 2918 - return -ENOIOCTLCMD; 2682 + struct gsm_dlci *dlci = tty->driver_data; 2683 + struct gsm_netconfig nc; 2684 + int index; 2685 + 2686 + switch (cmd) { 2687 + case GSMIOC_ENABLE_NET: 2688 + if (copy_from_user(&nc, (void __user *)arg, sizeof(nc))) 2689 + return -EFAULT; 2690 + nc.if_name[IFNAMSIZ-1] = '\0'; 2691 + /* return net interface index or error code */ 2692 + mutex_lock(&dlci->mutex); 2693 + index = gsm_create_network(dlci, &nc); 2694 + mutex_unlock(&dlci->mutex); 2695 + if (copy_to_user((void __user *)arg, &nc, sizeof(nc))) 2696 + return -EFAULT; 2697 + return index; 2698 + case GSMIOC_DISABLE_NET: 2699 + if (!capable(CAP_NET_ADMIN)) 2700 + return -EPERM; 2701 + mutex_lock(&dlci->mutex); 2702 + gsm_destroy_network(dlci); 2703 + mutex_unlock(&dlci->mutex); 2704 + return 0; 2705 + default: 2706 + return -ENOIOCTLCMD; 2707 + } 2919 2708 } 2920 2709 2921 2710 static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
+11
include/linux/gsmmux.h
··· 21 21 #define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config) 22 22 #define GSMIOC_SETCONF _IOW('G', 1, struct gsm_config) 23 23 24 + struct 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 36 #endif