~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/atm/atmtcp.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* drivers/atm/atmtcp.c - ATM over TCP "device" driver */
  2 
  3 /* Written 1997-2000 by Werner Almesberger, EPFL LRC/ICA */
  4 
  5 
  6 #include <linux/module.h>
  7 #include <linux/wait.h>
  8 #include <linux/atmdev.h>
  9 #include <linux/atm_tcp.h>
 10 #include <linux/bitops.h>
 11 #include <asm/uaccess.h>
 12 #include <asm/atomic.h>
 13 
 14 
 15 extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */
 16 
 17 
 18 #define PRIV(dev) ((struct atmtcp_dev_data *) ((dev)->dev_data))
 19 
 20 
 21 struct atmtcp_dev_data {
 22         struct atm_vcc *vcc;    /* control VCC; NULL if detached */
 23         int persist;            /* non-zero if persistent */
 24 };
 25 
 26 
 27 #define DEV_LABEL    "atmtcp"
 28 
 29 #define MAX_VPI_BITS  8 /* simplifies life */
 30 #define MAX_VCI_BITS 16
 31 
 32 
 33 /*
 34  * Hairy code ahead: the control VCC may be closed while we're still
 35  * waiting for an answer, so we need to re-validate out_vcc every once
 36  * in a while.
 37  */
 38 
 39 
 40 static int atmtcp_send_control(struct atm_vcc *vcc,int type,
 41     const struct atmtcp_control *msg,int flag)
 42 {
 43         DECLARE_WAITQUEUE(wait,current);
 44         struct atm_vcc *out_vcc;
 45         struct sk_buff *skb;
 46         struct atmtcp_control *new_msg;
 47         int old_test;
 48         int error = 0;
 49 
 50         out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
 51         if (!out_vcc) return -EUNATCH;
 52         skb = alloc_skb(sizeof(*msg),GFP_KERNEL);
 53         if (!skb) return -ENOMEM;
 54         mb();
 55         out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
 56         if (!out_vcc) {
 57                 dev_kfree_skb(skb);
 58                 return -EUNATCH;
 59         }
 60         atm_force_charge(out_vcc,skb->truesize);
 61         new_msg = (struct atmtcp_control *) skb_put(skb,sizeof(*new_msg));
 62         *new_msg = *msg;
 63         new_msg->hdr.length = ATMTCP_HDR_MAGIC;
 64         new_msg->type = type;
 65         memset(&new_msg->vcc,0,sizeof(atm_kptr_t));
 66         *(struct atm_vcc **) &new_msg->vcc = vcc;
 67         old_test = test_bit(flag,&vcc->flags);
 68         out_vcc->push(out_vcc,skb);
 69         add_wait_queue(&vcc->sleep,&wait);
 70         while (test_bit(flag,&vcc->flags) == old_test) {
 71                 mb();
 72                 out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
 73                 if (!out_vcc) {
 74                         error = -EUNATCH;
 75                         break;
 76                 }
 77                 set_current_state(TASK_UNINTERRUPTIBLE);
 78                 schedule();
 79         }
 80         current->state = TASK_RUNNING;
 81         remove_wait_queue(&vcc->sleep,&wait);
 82         return error;
 83 }
 84 
 85 
 86 static int atmtcp_recv_control(const struct atmtcp_control *msg)
 87 {
 88         struct atm_vcc *vcc = *(struct atm_vcc **) &msg->vcc;
 89 
 90         vcc->vpi = msg->addr.sap_addr.vpi;
 91         vcc->vci = msg->addr.sap_addr.vci;
 92         vcc->qos = msg->qos;
 93         vcc->reply = msg->result;
 94         switch (msg->type) {
 95             case ATMTCP_CTRL_OPEN:
 96                 change_bit(ATM_VF_READY,&vcc->flags);
 97                 break;
 98             case ATMTCP_CTRL_CLOSE:
 99                 change_bit(ATM_VF_ADDR,&vcc->flags);
100                 break;
101             default:
102                 printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n",
103                     msg->type);
104                 return -EINVAL;
105         }
106         wake_up(&vcc->sleep);
107         return 0;
108 }
109 
110 
111 static void atmtcp_v_dev_close(struct atm_dev *dev)
112 {
113         /* Nothing.... Isn't this simple :-)  -- REW */
114 }
115 
116 
117 static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci)
118 {
119         struct atmtcp_control msg;
120         int error;
121 
122         memset(&msg,0,sizeof(msg));
123         msg.addr.sap_family = AF_ATMPVC;
124         msg.hdr.vpi = htons(vpi);
125         msg.addr.sap_addr.vpi = vpi;
126         msg.hdr.vci = htons(vci);
127         msg.addr.sap_addr.vci = vci;
128         error = atm_find_ci(vcc,&msg.addr.sap_addr.vpi,&msg.addr.sap_addr.vci);
129         if (error) return error;
130         if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0;
131         msg.type = ATMTCP_CTRL_OPEN;
132         msg.qos = vcc->qos;
133         set_bit(ATM_VF_ADDR,&vcc->flags);
134         clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */
135         error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY);
136         if (error) return error;
137         return vcc->reply;
138 }
139 
140 
141 static void atmtcp_v_close(struct atm_vcc *vcc)
142 {
143         struct atmtcp_control msg;
144 
145         memset(&msg,0,sizeof(msg));
146         msg.addr.sap_family = AF_ATMPVC;
147         msg.addr.sap_addr.vpi = vcc->vpi;
148         msg.addr.sap_addr.vci = vcc->vci;
149         clear_bit(ATM_VF_READY,&vcc->flags);
150         (void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR);
151 }
152 
153 
154 static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
155 {
156         struct atm_cirange ci;
157         struct atm_vcc *vcc;
158 
159         if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD;
160         if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT;
161         if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS;
162         if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
163         if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
164             ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
165         for (vcc = dev->vccs; vcc; vcc = vcc->next)
166                 if ((vcc->vpi >> ci.vpi_bits) ||
167                     (vcc->vci >> ci.vci_bits)) return -EBUSY;
168         dev->ci_range = ci;
169         return 0;
170 }
171 
172 
173 static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
174 {
175         struct atmtcp_dev_data *dev_data;
176         struct atm_vcc *out_vcc;
177         struct sk_buff *new_skb;
178         struct atmtcp_hdr *hdr;
179         int size;
180 
181         if (vcc->qos.txtp.traffic_class == ATM_NONE) {
182                 if (vcc->pop) vcc->pop(vcc,skb);
183                 else dev_kfree_skb(skb);
184                 return -EINVAL;
185         }
186         dev_data = PRIV(vcc->dev);
187         if (dev_data) out_vcc = dev_data->vcc;
188         if (!dev_data || !out_vcc) {
189                 if (vcc->pop) vcc->pop(vcc,skb);
190                 else dev_kfree_skb(skb);
191                 if (dev_data) return 0;
192                 atomic_inc(&vcc->stats->tx_err);
193                 return -ENOLINK;
194         }
195         size = skb->len+sizeof(struct atmtcp_hdr);
196         new_skb = atm_alloc_charge(out_vcc,size,GFP_ATOMIC);
197         if (!new_skb) {
198                 if (vcc->pop) vcc->pop(vcc,skb);
199                 else dev_kfree_skb(skb);
200                 atomic_inc(&vcc->stats->tx_err);
201                 return -ENOBUFS;
202         }
203         hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr));
204         hdr->vpi = htons(vcc->vpi);
205         hdr->vci = htons(vcc->vci);
206         hdr->length = htonl(skb->len);
207         memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
208         if (vcc->pop) vcc->pop(vcc,skb);
209         else dev_kfree_skb(skb);
210         out_vcc->push(out_vcc,new_skb);
211         atomic_inc(&vcc->stats->tx);
212         atomic_inc(&out_vcc->stats->rx);
213         return 0;
214 }
215 
216 
217 static int atmtcp_v_proc(struct atm_dev *dev,loff_t *pos,char *page)
218 {
219         struct atmtcp_dev_data *dev_data = PRIV(dev);
220 
221         if (*pos) return 0;
222         if (!dev_data->persist) return sprintf(page,"ephemeral\n");
223         return sprintf(page,"persistent, %sconnected\n",
224             dev_data->vcc ? "" : "dis");
225 }
226 
227 
228 static void atmtcp_c_close(struct atm_vcc *vcc)
229 {
230         struct atm_dev *atmtcp_dev;
231         struct atmtcp_dev_data *dev_data;
232         struct atm_vcc *walk;
233 
234         atmtcp_dev = (struct atm_dev *) vcc->dev_data;
235         dev_data = PRIV(atmtcp_dev);
236         dev_data->vcc = NULL;
237         if (dev_data->persist) return;
238         PRIV(atmtcp_dev) = NULL;
239         kfree(dev_data);
240         shutdown_atm_dev(atmtcp_dev);
241         vcc->dev_data = NULL;
242         for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
243                 wake_up(&walk->sleep);
244 }
245 
246 
247 static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
248 {
249         struct atm_dev *dev;
250         struct atmtcp_hdr *hdr;
251         struct atm_vcc *out_vcc;
252         struct sk_buff *new_skb;
253         int result = 0;
254 
255         if (!skb->len) return 0;
256         dev = vcc->dev_data;
257         hdr = (struct atmtcp_hdr *) skb->data;
258         if (hdr->length == ATMTCP_HDR_MAGIC) {
259                 result = atmtcp_recv_control(
260                     (struct atmtcp_control *) skb->data);
261                 goto done;
262         }
263         for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
264                 if (out_vcc->vpi == ntohs(hdr->vpi) &&
265                     out_vcc->vci == ntohs(hdr->vci) &&
266                     out_vcc->qos.rxtp.traffic_class != ATM_NONE)
267                         break;
268         if (!out_vcc) {
269                 atomic_inc(&vcc->stats->tx_err);
270                 goto done;
271         }
272         skb_pull(skb,sizeof(struct atmtcp_hdr));
273         new_skb = atm_alloc_charge(out_vcc,skb->len,GFP_KERNEL);
274         if (!new_skb) {
275                 result = -ENOBUFS;
276                 goto done;
277         }
278         new_skb->stamp = xtime;
279         memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
280         out_vcc->push(out_vcc,new_skb);
281         atomic_inc(&vcc->stats->tx);
282         atomic_inc(&out_vcc->stats->rx);
283 done:
284         if (vcc->pop) vcc->pop(vcc,skb);
285         else dev_kfree_skb(skb);
286         return result;
287 }
288 
289 
290 /*
291  * Device operations for the virtual ATM devices created by ATMTCP.
292  */
293 
294 
295 static struct atmdev_ops atmtcp_v_dev_ops = {
296         dev_close:      atmtcp_v_dev_close,
297         open:           atmtcp_v_open,
298         close:          atmtcp_v_close,
299         ioctl:          atmtcp_v_ioctl,
300         send:           atmtcp_v_send,
301         proc_read:      atmtcp_v_proc,
302         owner:          THIS_MODULE
303 };
304 
305 
306 /*
307  * Device operations for the ATMTCP control device.
308  */
309 
310 
311 static struct atmdev_ops atmtcp_c_dev_ops = {
312         close:          atmtcp_c_close,
313         send:           atmtcp_c_send
314 };
315 
316 
317 static struct atm_dev atmtcp_control_dev = {
318         &atmtcp_c_dev_ops,
319         NULL,           /* no PHY */
320         "atmtcp",       /* type */
321         999,            /* dummy device number */
322         NULL,NULL,      /* pretend not to have any VCCs */
323         NULL,NULL,      /* no data */
324         { 0 },          /* no flags */
325         NULL,           /* no local address */
326         { 0 }           /* no ESI, no statistics */
327 };
328 
329 
330 static int atmtcp_create(int itf,int persist,struct atm_dev **result)
331 {
332         struct atmtcp_dev_data *dev_data;
333         struct atm_dev *dev;
334 
335         dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
336         if (!dev_data)
337                 return -ENOMEM;
338 
339         dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
340         if (!dev) {
341                 kfree(dev_data);
342                 return itf == -1 ? -ENOMEM : -EBUSY;
343         }
344         dev->ci_range.vpi_bits = MAX_VPI_BITS;
345         dev->ci_range.vci_bits = MAX_VCI_BITS;
346         PRIV(dev) = dev_data;
347         PRIV(dev)->vcc = NULL;
348         PRIV(dev)->persist = persist;
349         if (result) *result = dev;
350         return 0;
351 }
352 
353 
354 int atmtcp_attach(struct atm_vcc *vcc,int itf)
355 {
356         struct atm_dev *dev;
357 
358         dev = NULL;
359         if (itf != -1) dev = atm_find_dev(itf);
360         if (dev) {
361                 if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
362                 if (PRIV(dev)->vcc) return -EBUSY;
363         }
364         else {
365                 int error;
366 
367                 error = atmtcp_create(itf,0,&dev);
368                 if (error) return error;
369         }
370         PRIV(dev)->vcc = vcc;
371         bind_vcc(vcc,&atmtcp_control_dev);
372         set_bit(ATM_VF_META,&vcc->flags);
373         set_bit(ATM_VF_READY,&vcc->flags);
374         vcc->dev_data = dev;
375         (void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */
376         vcc->stats = &atmtcp_control_dev.stats.aal5;
377         return dev->number;
378 }
379 
380 
381 int atmtcp_create_persistent(int itf)
382 {
383         return atmtcp_create(itf,1,NULL);
384 }
385 
386 
387 int atmtcp_remove_persistent(int itf)
388 {
389         struct atm_dev *dev;
390         struct atmtcp_dev_data *dev_data;
391 
392         dev = atm_find_dev(itf);
393         if (!dev) return -ENODEV;
394         if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
395         dev_data = PRIV(dev);
396         if (!dev_data->persist) return 0;
397         dev_data->persist = 0;
398         if (PRIV(dev)->vcc) return 0;
399         kfree(dev_data);
400         shutdown_atm_dev(dev);
401         return 0;
402 }
403 
404 
405 #ifdef MODULE
406 
407 int init_module(void)
408 {
409         atm_tcp_ops.attach = atmtcp_attach;
410         atm_tcp_ops.create_persistent = atmtcp_create_persistent;
411         atm_tcp_ops.remove_persistent = atmtcp_remove_persistent;
412         return 0;
413 }
414 
415 
416 void cleanup_module(void)
417 {
418         atm_tcp_ops.attach = NULL;
419         atm_tcp_ops.create_persistent = NULL;
420         atm_tcp_ops.remove_persistent = NULL;
421 }
422 
423 #else
424 
425 struct atm_tcp_ops atm_tcp_ops = {
426         atmtcp_attach,                  /* attach */
427         atmtcp_create_persistent,       /* create_persistent */
428         atmtcp_remove_persistent        /* remove_persistent */
429 };
430 
431 #endif
432 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.