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

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.12-rc2 219 lines 4.5 kB view raw
1/* 2 * Generic HDLC support routines for Linux 3 * X.25 support 4 * 5 * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of version 2 of the GNU General Public License 9 * as published by the Free Software Foundation. 10 */ 11 12#include <linux/module.h> 13#include <linux/kernel.h> 14#include <linux/slab.h> 15#include <linux/poll.h> 16#include <linux/errno.h> 17#include <linux/if_arp.h> 18#include <linux/init.h> 19#include <linux/skbuff.h> 20#include <linux/pkt_sched.h> 21#include <linux/inetdevice.h> 22#include <linux/lapb.h> 23#include <linux/rtnetlink.h> 24#include <linux/hdlc.h> 25 26#include <net/x25device.h> 27 28/* These functions are callbacks called by LAPB layer */ 29 30static void x25_connect_disconnect(struct net_device *dev, int reason, int code) 31{ 32 struct sk_buff *skb; 33 unsigned char *ptr; 34 35 if ((skb = dev_alloc_skb(1)) == NULL) { 36 printk(KERN_ERR "%s: out of memory\n", dev->name); 37 return; 38 } 39 40 ptr = skb_put(skb, 1); 41 *ptr = code; 42 43 skb->protocol = x25_type_trans(skb, dev); 44 netif_rx(skb); 45} 46 47 48 49static void x25_connected(struct net_device *dev, int reason) 50{ 51 x25_connect_disconnect(dev, reason, 1); 52} 53 54 55 56static void x25_disconnected(struct net_device *dev, int reason) 57{ 58 x25_connect_disconnect(dev, reason, 2); 59} 60 61 62 63static int x25_data_indication(struct net_device *dev, struct sk_buff *skb) 64{ 65 unsigned char *ptr; 66 67 skb_push(skb, 1); 68 69 if (skb_cow(skb, 1)) 70 return NET_RX_DROP; 71 72 ptr = skb->data; 73 *ptr = 0; 74 75 skb->protocol = x25_type_trans(skb, dev); 76 return netif_rx(skb); 77} 78 79 80 81static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb) 82{ 83 hdlc_device *hdlc = dev_to_hdlc(dev); 84 hdlc->xmit(skb, dev); /* Ignore return value :-( */ 85} 86 87 88 89static int x25_xmit(struct sk_buff *skb, struct net_device *dev) 90{ 91 int result; 92 93 94 /* X.25 to LAPB */ 95 switch (skb->data[0]) { 96 case 0: /* Data to be transmitted */ 97 skb_pull(skb, 1); 98 if ((result = lapb_data_request(dev, skb)) != LAPB_OK) 99 dev_kfree_skb(skb); 100 return 0; 101 102 case 1: 103 if ((result = lapb_connect_request(dev))!= LAPB_OK) { 104 if (result == LAPB_CONNECTED) 105 /* Send connect confirm. msg to level 3 */ 106 x25_connected(dev, 0); 107 else 108 printk(KERN_ERR "%s: LAPB connect request " 109 "failed, error code = %i\n", 110 dev->name, result); 111 } 112 break; 113 114 case 2: 115 if ((result = lapb_disconnect_request(dev)) != LAPB_OK) { 116 if (result == LAPB_NOTCONNECTED) 117 /* Send disconnect confirm. msg to level 3 */ 118 x25_disconnected(dev, 0); 119 else 120 printk(KERN_ERR "%s: LAPB disconnect request " 121 "failed, error code = %i\n", 122 dev->name, result); 123 } 124 break; 125 126 default: /* to be defined */ 127 break; 128 } 129 130 dev_kfree_skb(skb); 131 return 0; 132} 133 134 135 136static int x25_open(struct net_device *dev) 137{ 138 struct lapb_register_struct cb; 139 int result; 140 141 cb.connect_confirmation = x25_connected; 142 cb.connect_indication = x25_connected; 143 cb.disconnect_confirmation = x25_disconnected; 144 cb.disconnect_indication = x25_disconnected; 145 cb.data_indication = x25_data_indication; 146 cb.data_transmit = x25_data_transmit; 147 148 result = lapb_register(dev, &cb); 149 if (result != LAPB_OK) 150 return result; 151 return 0; 152} 153 154 155 156static void x25_close(struct net_device *dev) 157{ 158 lapb_unregister(dev); 159} 160 161 162 163static int x25_rx(struct sk_buff *skb) 164{ 165 hdlc_device *hdlc = dev_to_hdlc(skb->dev); 166 167 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { 168 hdlc->stats.rx_dropped++; 169 return NET_RX_DROP; 170 } 171 172 if (lapb_data_received(skb->dev, skb) == LAPB_OK) 173 return NET_RX_SUCCESS; 174 175 hdlc->stats.rx_errors++; 176 dev_kfree_skb_any(skb); 177 return NET_RX_DROP; 178} 179 180 181 182int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) 183{ 184 hdlc_device *hdlc = dev_to_hdlc(dev); 185 int result; 186 187 switch (ifr->ifr_settings.type) { 188 case IF_GET_PROTO: 189 ifr->ifr_settings.type = IF_PROTO_X25; 190 return 0; /* return protocol only, no settable parameters */ 191 192 case IF_PROTO_X25: 193 if(!capable(CAP_NET_ADMIN)) 194 return -EPERM; 195 196 if(dev->flags & IFF_UP) 197 return -EBUSY; 198 199 result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); 200 if (result) 201 return result; 202 203 hdlc_proto_detach(hdlc); 204 memset(&hdlc->proto, 0, sizeof(hdlc->proto)); 205 206 hdlc->proto.open = x25_open; 207 hdlc->proto.close = x25_close; 208 hdlc->proto.netif_rx = x25_rx; 209 hdlc->proto.type_trans = NULL; 210 hdlc->proto.id = IF_PROTO_X25; 211 dev->hard_start_xmit = x25_xmit; 212 dev->hard_header = NULL; 213 dev->type = ARPHRD_X25; 214 dev->addr_len = 0; 215 return 0; 216 } 217 218 return -EINVAL; 219}