root/drivers/net/wan/hdlc_x25.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. x25_connect_disconnect
  2. x25_connected
  3. x25_disconnected
  4. x25_data_indication
  5. x25_data_transmit
  6. x25_xmit
  7. x25_open
  8. x25_close
  9. x25_rx
  10. x25_ioctl
  11. mod_init
  12. mod_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Generic HDLC support routines for Linux
   4  * X.25 support
   5  *
   6  * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
   7  */
   8 
   9 #include <linux/errno.h>
  10 #include <linux/gfp.h>
  11 #include <linux/hdlc.h>
  12 #include <linux/if_arp.h>
  13 #include <linux/inetdevice.h>
  14 #include <linux/init.h>
  15 #include <linux/kernel.h>
  16 #include <linux/lapb.h>
  17 #include <linux/module.h>
  18 #include <linux/pkt_sched.h>
  19 #include <linux/poll.h>
  20 #include <linux/rtnetlink.h>
  21 #include <linux/skbuff.h>
  22 #include <net/x25device.h>
  23 
  24 static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
  25 
  26 /* These functions are callbacks called by LAPB layer */
  27 
  28 static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
  29 {
  30         struct sk_buff *skb;
  31         unsigned char *ptr;
  32 
  33         if ((skb = dev_alloc_skb(1)) == NULL) {
  34                 netdev_err(dev, "out of memory\n");
  35                 return;
  36         }
  37 
  38         ptr = skb_put(skb, 1);
  39         *ptr = code;
  40 
  41         skb->protocol = x25_type_trans(skb, dev);
  42         netif_rx(skb);
  43 }
  44 
  45 
  46 
  47 static void x25_connected(struct net_device *dev, int reason)
  48 {
  49         x25_connect_disconnect(dev, reason, X25_IFACE_CONNECT);
  50 }
  51 
  52 
  53 
  54 static void x25_disconnected(struct net_device *dev, int reason)
  55 {
  56         x25_connect_disconnect(dev, reason, X25_IFACE_DISCONNECT);
  57 }
  58 
  59 
  60 
  61 static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
  62 {
  63         unsigned char *ptr;
  64 
  65         if (skb_cow(skb, 1))
  66                 return NET_RX_DROP;
  67 
  68         skb_push(skb, 1);
  69         skb_reset_network_header(skb);
  70 
  71         ptr  = skb->data;
  72         *ptr = X25_IFACE_DATA;
  73 
  74         skb->protocol = x25_type_trans(skb, dev);
  75         return netif_rx(skb);
  76 }
  77 
  78 
  79 
  80 static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
  81 {
  82         hdlc_device *hdlc = dev_to_hdlc(dev);
  83 
  84         skb_reset_network_header(skb);
  85         skb->protocol = hdlc_type_trans(skb, dev);
  86 
  87         if (dev_nit_active(dev))
  88                 dev_queue_xmit_nit(skb, dev);
  89 
  90         hdlc->xmit(skb, dev); /* Ignore return value :-( */
  91 }
  92 
  93 
  94 
  95 static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
  96 {
  97         int result;
  98 
  99 
 100         /* X.25 to LAPB */
 101         switch (skb->data[0]) {
 102         case X25_IFACE_DATA:    /* Data to be transmitted */
 103                 skb_pull(skb, 1);
 104                 skb_reset_network_header(skb);
 105                 if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
 106                         dev_kfree_skb(skb);
 107                 return NETDEV_TX_OK;
 108 
 109         case X25_IFACE_CONNECT:
 110                 if ((result = lapb_connect_request(dev))!= LAPB_OK) {
 111                         if (result == LAPB_CONNECTED)
 112                                 /* Send connect confirm. msg to level 3 */
 113                                 x25_connected(dev, 0);
 114                         else
 115                                 netdev_err(dev, "LAPB connect request failed, error code = %i\n",
 116                                            result);
 117                 }
 118                 break;
 119 
 120         case X25_IFACE_DISCONNECT:
 121                 if ((result = lapb_disconnect_request(dev)) != LAPB_OK) {
 122                         if (result == LAPB_NOTCONNECTED)
 123                                 /* Send disconnect confirm. msg to level 3 */
 124                                 x25_disconnected(dev, 0);
 125                         else
 126                                 netdev_err(dev, "LAPB disconnect request failed, error code = %i\n",
 127                                            result);
 128                 }
 129                 break;
 130 
 131         default:                /* to be defined */
 132                 break;
 133         }
 134 
 135         dev_kfree_skb(skb);
 136         return NETDEV_TX_OK;
 137 }
 138 
 139 
 140 
 141 static int x25_open(struct net_device *dev)
 142 {
 143         int result;
 144         static const struct lapb_register_struct cb = {
 145                 .connect_confirmation = x25_connected,
 146                 .connect_indication = x25_connected,
 147                 .disconnect_confirmation = x25_disconnected,
 148                 .disconnect_indication = x25_disconnected,
 149                 .data_indication = x25_data_indication,
 150                 .data_transmit = x25_data_transmit,
 151         };
 152 
 153         result = lapb_register(dev, &cb);
 154         if (result != LAPB_OK)
 155                 return result;
 156         return 0;
 157 }
 158 
 159 
 160 
 161 static void x25_close(struct net_device *dev)
 162 {
 163         lapb_unregister(dev);
 164 }
 165 
 166 
 167 
 168 static int x25_rx(struct sk_buff *skb)
 169 {
 170         struct net_device *dev = skb->dev;
 171 
 172         if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
 173                 dev->stats.rx_dropped++;
 174                 return NET_RX_DROP;
 175         }
 176 
 177         if (lapb_data_received(dev, skb) == LAPB_OK)
 178                 return NET_RX_SUCCESS;
 179 
 180         dev->stats.rx_errors++;
 181         dev_kfree_skb_any(skb);
 182         return NET_RX_DROP;
 183 }
 184 
 185 
 186 static struct hdlc_proto proto = {
 187         .open           = x25_open,
 188         .close          = x25_close,
 189         .ioctl          = x25_ioctl,
 190         .netif_rx       = x25_rx,
 191         .xmit           = x25_xmit,
 192         .module         = THIS_MODULE,
 193 };
 194 
 195 
 196 static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
 197 {
 198         hdlc_device *hdlc = dev_to_hdlc(dev);
 199         int result;
 200 
 201         switch (ifr->ifr_settings.type) {
 202         case IF_GET_PROTO:
 203                 if (dev_to_hdlc(dev)->proto != &proto)
 204                         return -EINVAL;
 205                 ifr->ifr_settings.type = IF_PROTO_X25;
 206                 return 0; /* return protocol only, no settable parameters */
 207 
 208         case IF_PROTO_X25:
 209                 if (!capable(CAP_NET_ADMIN))
 210                         return -EPERM;
 211 
 212                 if (dev->flags & IFF_UP)
 213                         return -EBUSY;
 214 
 215                 result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
 216                 if (result)
 217                         return result;
 218 
 219                 if ((result = attach_hdlc_protocol(dev, &proto, 0)))
 220                         return result;
 221                 dev->type = ARPHRD_X25;
 222                 call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
 223                 netif_dormant_off(dev);
 224                 return 0;
 225         }
 226 
 227         return -EINVAL;
 228 }
 229 
 230 
 231 static int __init mod_init(void)
 232 {
 233         register_hdlc_protocol(&proto);
 234         return 0;
 235 }
 236 
 237 
 238 
 239 static void __exit mod_exit(void)
 240 {
 241         unregister_hdlc_protocol(&proto);
 242 }
 243 
 244 
 245 module_init(mod_init);
 246 module_exit(mod_exit);
 247 
 248 MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
 249 MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");
 250 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */