Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
isdn_x25iface.c
Go to the documentation of this file.
1 /* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2  *
3  * Linux ISDN subsystem, X.25 related functions
4  *
5  * This software may be used and distributed according to the terms
6  * of the GNU General Public License, incorporated herein by reference.
7  *
8  * stuff needed to support the Linux X.25 PLP code on top of devices that
9  * can provide a lab_b service using the concap_proto mechanism.
10  * This module supports a network interface which provides lapb_sematics
11  * -- as defined in Documentation/networking/x25-iface.txt -- to
12  * the upper layer and assumes that the lower layer provides a reliable
13  * data link service by means of the concap_device_ops callbacks.
14  *
15  * Only protocol specific stuff goes here. Device specific stuff
16  * goes to another -- device related -- concap_proto support source file.
17  *
18  */
19 
20 /* #include <linux/isdn.h> */
21 #include <linux/netdevice.h>
22 #include <linux/concap.h>
23 #include <linux/slab.h>
24 #include <linux/wanrouter.h>
25 #include <net/x25device.h>
26 #include "isdn_x25iface.h"
27 
28 /* for debugging messages not to cause an oops when device pointer is NULL*/
29 #define MY_DEVNAME(dev) ((dev) ? (dev)->name : "DEVICE UNSPECIFIED")
30 
31 
32 typedef struct isdn_x25iface_proto_data {
33  int magic;
35  /* Private stuff, not to be accessed via proto_data. We provide the
36  other storage for the concap_proto instance here as well,
37  enabling us to allocate both with just one kmalloc(): */
39 } ix25_pdata_t;
40 
41 
42 
43 /* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
44 static void isdn_x25iface_proto_del(struct concap_proto *);
45 static int isdn_x25iface_proto_close(struct concap_proto *);
46 static int isdn_x25iface_proto_restart(struct concap_proto *,
47  struct net_device *,
48  struct concap_device_ops *);
49 static int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *);
50 static int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *);
51 static int isdn_x25iface_connect_ind(struct concap_proto *);
52 static int isdn_x25iface_disconn_ind(struct concap_proto *);
53 
54 
55 static struct concap_proto_ops ix25_pops = {
57  &isdn_x25iface_proto_del,
58  &isdn_x25iface_proto_restart,
59  &isdn_x25iface_proto_close,
60  &isdn_x25iface_xmit,
61  &isdn_x25iface_receive,
62  &isdn_x25iface_connect_ind,
63  &isdn_x25iface_disconn_ind
64 };
65 
66 /* error message helper function */
67 static void illegal_state_warn(unsigned state, unsigned char firstbyte)
68 {
69  printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
70  "current state %d\n", firstbyte, state);
71 }
72 
73 /* check protocol data field for consistency */
74 static int pdata_is_bad(ix25_pdata_t *pda) {
75 
76  if (pda && pda->magic == ISDN_X25IFACE_MAGIC) return 0;
78  "isdn_x25iface_xxx: illegal pointer to proto data\n");
79  return 1;
80 }
81 
82 /* create a new x25 interface protocol instance
83  */
85 {
87  IX25DEBUG("isdn_x25iface_proto_new\n");
88  if (tmp) {
90  tmp->state = WAN_UNCONFIGURED;
91  /* private data space used to hold the concap_proto data.
92  Only to be accessed via the returned pointer */
93  spin_lock_init(&tmp->priv.lock);
94  tmp->priv.dops = NULL;
95  tmp->priv.net_dev = NULL;
96  tmp->priv.pops = &ix25_pops;
97  tmp->priv.flags = 0;
98  tmp->priv.proto_data = tmp;
99  return (&(tmp->priv));
100  }
101  return NULL;
102 };
103 
104 /* close the x25iface encapsulation protocol
105  */
106 static int isdn_x25iface_proto_close(struct concap_proto *cprot) {
107 
108  ix25_pdata_t *tmp;
109  int ret = 0;
110  ulong flags;
111 
112  if (!cprot) {
113  printk(KERN_ERR "isdn_x25iface_proto_close: "
114  "invalid concap_proto pointer\n");
115  return -1;
116  }
117  IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev));
118  spin_lock_irqsave(&cprot->lock, flags);
119  cprot->dops = NULL;
120  cprot->net_dev = NULL;
121  tmp = cprot->proto_data;
122  if (pdata_is_bad(tmp)) {
123  ret = -1;
124  } else {
125  tmp->state = WAN_UNCONFIGURED;
126  }
127  spin_unlock_irqrestore(&cprot->lock, flags);
128  return ret;
129 }
130 
131 /* Delete the x25iface encapsulation protocol instance
132  */
133 static void isdn_x25iface_proto_del(struct concap_proto *cprot) {
134 
135  ix25_pdata_t *tmp;
136 
137  IX25DEBUG("isdn_x25iface_proto_del \n");
138  if (!cprot) {
139  printk(KERN_ERR "isdn_x25iface_proto_del: "
140  "concap_proto pointer is NULL\n");
141  return;
142  }
143  tmp = cprot->proto_data;
144  if (tmp == NULL) {
145  printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent "
146  "proto_data pointer (maybe already deleted?)\n");
147  return;
148  }
149  /* close if the protocol is still open */
150  if (cprot->dops) isdn_x25iface_proto_close(cprot);
151  /* freeing the storage should be sufficient now. But some additional
152  settings might help to catch wild pointer bugs */
153  tmp->magic = 0;
154  cprot->proto_data = NULL;
155 
156  kfree(tmp);
157  return;
158 }
159 
160 /* (re-)initialize the data structures for x25iface encapsulation
161  */
162 static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
163  struct net_device *ndev,
164  struct concap_device_ops *dops)
165 {
166  ix25_pdata_t *pda = cprot->proto_data;
167  ulong flags;
168 
169  IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev));
170 
171  if (pdata_is_bad(pda)) return -1;
172 
173  if (!(dops && dops->data_req && dops->connect_req
174  && dops->disconn_req)) {
175  printk(KERN_WARNING "isdn_x25iface_restart: required dops"
176  " missing\n");
177  isdn_x25iface_proto_close(cprot);
178  return -1;
179  }
180  spin_lock_irqsave(&cprot->lock, flags);
181  cprot->net_dev = ndev;
182  cprot->pops = &ix25_pops;
183  cprot->dops = dops;
184  pda->state = WAN_DISCONNECTED;
185  spin_unlock_irqrestore(&cprot->lock, flags);
186  return 0;
187 }
188 
189 /* deliver a dl_data frame received from i4l HL driver to the network layer
190  */
191 static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
192 {
193  IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev));
194  if (((ix25_pdata_t *)(cprot->proto_data))
195  ->state == WAN_CONNECTED) {
196  if (skb_push(skb, 1)) {
197  skb->data[0] = X25_IFACE_DATA;
198  skb->protocol = x25_type_trans(skb, cprot->net_dev);
199  netif_rx(skb);
200  return 0;
201  }
202  }
203  printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev));
204  dev_kfree_skb(skb);
205  return -1;
206 }
207 
208 /* a connection set up is indicated by lower layer
209  */
210 static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
211 {
212  struct sk_buff *skb;
213  enum wan_states *state_p
214  = &(((ix25_pdata_t *)(cprot->proto_data))->state);
215  IX25DEBUG("isdn_x25iface_connect_ind %s \n"
216  , MY_DEVNAME(cprot->net_dev));
217  if (*state_p == WAN_UNCONFIGURED) {
219  "isdn_x25iface_connect_ind while unconfigured %s\n"
220  , MY_DEVNAME(cprot->net_dev));
221  return -1;
222  }
223  *state_p = WAN_CONNECTED;
224 
225  skb = dev_alloc_skb(1);
226  if (skb) {
227  *(skb_put(skb, 1)) = X25_IFACE_CONNECT;
228  skb->protocol = x25_type_trans(skb, cprot->net_dev);
229  netif_rx(skb);
230  return 0;
231  } else {
232  printk(KERN_WARNING "isdn_x25iface_connect_ind: "
233  " out of memory -- disconnecting\n");
234  cprot->dops->disconn_req(cprot);
235  return -1;
236  }
237 }
238 
239 /* a disconnect is indicated by lower layer
240  */
241 static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
242 {
243  struct sk_buff *skb;
244  enum wan_states *state_p
245  = &(((ix25_pdata_t *)(cprot->proto_data))->state);
246  IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev));
247  if (*state_p == WAN_UNCONFIGURED) {
249  "isdn_x25iface_disconn_ind while unconfigured\n");
250  return -1;
251  }
252  if (!cprot->net_dev) return -1;
253  *state_p = WAN_DISCONNECTED;
254  skb = dev_alloc_skb(1);
255  if (skb) {
256  *(skb_put(skb, 1)) = X25_IFACE_DISCONNECT;
257  skb->protocol = x25_type_trans(skb, cprot->net_dev);
258  netif_rx(skb);
259  return 0;
260  } else {
261  printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
262  " out of memory\n");
263  return -1;
264  }
265 }
266 
267 /* process a frame handed over to us from linux network layer. First byte
268  semantics as defined in Documentation/networking/x25-iface.txt
269 */
270 static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
271 {
272  unsigned char firstbyte = skb->data[0];
273  enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state;
274  int ret = 0;
275  IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n",
276  MY_DEVNAME(cprot->net_dev), firstbyte, *state);
277  switch (firstbyte) {
278  case X25_IFACE_DATA:
279  if (*state == WAN_CONNECTED) {
280  skb_pull(skb, 1);
281  cprot->net_dev->trans_start = jiffies;
282  ret = (cprot->dops->data_req(cprot, skb));
283  /* prepare for future retransmissions */
284  if (ret) skb_push(skb, 1);
285  return ret;
286  }
287  illegal_state_warn(*state, firstbyte);
288  break;
289  case X25_IFACE_CONNECT:
290  if (*state == WAN_DISCONNECTED) {
291  *state = WAN_CONNECTING;
292  ret = cprot->dops->connect_req(cprot);
293  if (ret) {
294  /* reset state and notify upper layer about
295  * immidiatly failed attempts */
296  isdn_x25iface_disconn_ind(cprot);
297  }
298  } else {
299  illegal_state_warn(*state, firstbyte);
300  }
301  break;
303  switch (*state) {
304  case WAN_DISCONNECTED:
305  /* Should not happen. However, give upper layer a
306  chance to recover from inconstistency but don't
307  trust the lower layer sending the disconn_confirm
308  when already disconnected */
309  printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
310  " requested while disconnected\n");
311  isdn_x25iface_disconn_ind(cprot);
312  break; /* prevent infinite loops */
313  case WAN_CONNECTING:
314  case WAN_CONNECTED:
315  *state = WAN_DISCONNECTED;
316  cprot->dops->disconn_req(cprot);
317  break;
318  default:
319  illegal_state_warn(*state, firstbyte);
320  }
321  break;
322  case X25_IFACE_PARAMS:
323  printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
324  " options not yet supported\n");
325  break;
326  default:
327  printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
328  " first byte %x ignored:\n", firstbyte);
329  }
330  dev_kfree_skb(skb);
331  return 0;
332 }