📄 af_wanpipe.c
字号:
/****************************************************************************** af_wanpipe.c WANPIPE(tm) Secure Socket Layer.** Author: Nenad Corbic <ncorbic@sangoma.com>** Copyright: (c) 2000 Sangoma Technologies Inc.** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version* 2 of the License, or (at your option) any later version.* ============================================================================* Due Credit:* Wanpipe socket layer is based on Packet and * the X25 socket layers. The above sockets were * used for the specific use of Sangoma Technoloiges * API programs. * Packet socket Authors: Ross Biro, Fred N. van Kempen and * Alan Cox.* X25 socket Author: Jonathan Naylor.* ============================================================================* Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets.* Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call.* Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem.* Server and client applicaton can run* simultaneously without conflicts.* Feb 29, 2000 Nenad Corbic o Added support for PVC protocols, such as* CHDLC, Frame Relay and HDLC API.* Jan 17, 2000 Nenad Corbic o Initial version, based on AF_PACKET socket.* X25API support only. *******************************************************************************/#include <linux/version.h>#include <linux/config.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/fcntl.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/poll.h>#include <linux/wireless.h>#include <linux/kmod.h>#include <net/ip.h>#include <net/protocol.h>#include <linux/skbuff.h>#include <net/sock.h>#include <linux/errno.h>#include <linux/timer.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/module.h>#include <linux/init.h>#include <linux/wanpipe.h>#include <linux/if_wanpipe.h>#include <linux/pkt_sched.h>#include <linux/tcp.h>#include <linux/if_wanpipe_common.h>#include <linux/sdla_x25.h>#ifdef CONFIG_INET#include <net/inet_common.h>#endif#define SLOW_BACKOFF 0.1*HZ#define FAST_BACKOFF 0.01*HZ//#define PRINT_DEBUG#ifdef PRINT_DEBUG #define DBG_PRINTK(format, a...) printk(format, ## a)#else #define DBG_PRINTK(format, a...)#endif #if defined(LINUX_2_1) #define dev_put(a) #define __sock_put(a) #define sock_hold(a) #define DECLARE_WAITQUEUE(a,b) \ struct wait_queue a = { b, NULL }#endif /* SECURE SOCKET IMPLEMENTATION * * TRANSMIT: * * When the user sends a packet via send() system call * the wanpipe_sendmsg() function is executed. * * Each packet is enqueud into sk->write_queue transmit * queue. When the packet is enqueued, a delayed transmit * timer is triggerd which acts as a Bottom Half hander. * * wanpipe_delay_transmit() function (BH), dequeues packets * from the sk->write_queue transmit queue and sends it * to the deriver via dev->hard_start_xmit(skb, dev) function. * Note, this function is actual a function pointer of if_send() * routine in the wanpipe driver. * * X25API GUARANTEED DELIVERY: * * In order to provide 100% guaranteed packet delivery, * an atomic 'packet_sent' counter is implemented. Counter * is incremented for each packet enqueued * into sk->write_queue. Counter is decremented each * time wanpipe_delayed_transmit() function successfuly * passes the packet to the driver. Before each send(), a poll * routine checks the sock resources The maximum value of * packet sent counter is 1, thus if one packet is queued, the * application will block untill that packet is passed to the * driver. * * RECEIVE: * * Wanpipe device drivers call the socket bottom half * function, wanpipe_rcv() to queue the incoming packets * into an AF_WANPIPE socket queue. Based on wanpipe_rcv() * return code, the driver knows whether the packet was * sucessfully queued. If the socket queue is full, * protocol flow control is used by the driver, if any, * to slow down the traffic untill the sock queue is free. * * Every time a packet arrives into a socket queue the * socket wakes up processes which are waiting to receive * data. * * If the socket queue is full, the driver sets a block * bit which signals the socket to kick the wanpipe driver * bottom half hander when the socket queue is partialy * empty. wanpipe_recvmsg() function performs this action. * * In case of x25api, packets will never be dropped, since * flow control is available. * * In case of streaming protocols like CHDLC, packets will * be dropped but the statistics will be generated. *//* The code below is used to test memory leaks. It prints out * a message every time kmalloc and kfree system calls get executed. * If the calls match there is no leak :) *//***********FOR DEBUGGING PURPOSES*********************************************#define KMEM_SAFETYZONE 8static void * dbg_kmalloc(unsigned int size, int prio, int line) { void * v = kmalloc(size,prio); printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); return v;}static void dbg_kfree(void * v, int line) { printk(KERN_INFO "line %d kfree(%p)\n",line,v); kfree(v);}#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)#define kfree(x) dbg_kfree(x,__LINE__)******************************************************************************//* List of all wanpipe sockets. */struct sock * wanpipe_sklist = NULL;static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED;atomic_t wanpipe_socks_nr;static unsigned long wanpipe_tx_critical=0;#if 0/* Private wanpipe socket structures. */struct wanpipe_opt{ void *mbox; /* Mail box */ void *card; /* Card bouded to */ netdevice_t *dev; /* Bounded device */ unsigned short lcn; /* Binded LCN */ unsigned char svc; /* 0=pvc, 1=svc */ unsigned char timer; /* flag for delayed transmit*/ struct timer_list tx_timer; unsigned poll_cnt; unsigned char force; /* Used to force sock release */ atomic_t packet_sent; };#endifstatic int sk_count=0;extern struct proto_ops wanpipe_ops;static unsigned long find_free_critical=0;static void wanpipe_unlink_driver (struct sock *);static void wanpipe_link_driver (netdevice_t *,struct sock *sk);static void wanpipe_wakeup_driver(struct sock *sk);static int execute_command(struct sock *, unsigned char, unsigned int);static int check_dev (netdevice_t *, sdla_t *);netdevice_t * wanpipe_find_free_dev (sdla_t *);static void wanpipe_unlink_card (struct sock *);static int wanpipe_link_card (struct sock *);static struct sock *wanpipe_make_new(struct sock *);static struct sock *wanpipe_alloc_socket(void);static inline int get_atomic_device (netdevice_t *);static int wanpipe_exec_cmd(struct sock *, int, unsigned int);static int get_ioctl_cmd (struct sock *, void *);static int set_ioctl_cmd (struct sock *, void *);static void release_device (netdevice_t *);static void wanpipe_kill_sock_timer (unsigned long data);static void wanpipe_kill_sock_irq (struct sock *);static void wanpipe_kill_sock_accept (struct sock *);static int wanpipe_do_bind(struct sock *, netdevice_t *, int);struct sock * get_newsk_from_skb (struct sk_buff *);static int wanpipe_debug (struct sock *, void *);static void wanpipe_delayed_transmit (unsigned long data);static void release_driver(struct sock *);static void start_cleanup_timer (struct sock *);static void check_write_queue(struct sock *);static int check_driver_busy (struct sock *);/*============================================================ * wanpipe_rcv * * Wanpipe socket bottom half handler. This function * is called by the WANPIPE device drivers to queue a * incomming packet into the socket receive queue. * Once the packet is queued, all processes waiting to * read are woken up. * * During socket bind, this function is bounded into * WANPIPE driver private. *===========================================================*/static int wanpipe_rcv(struct sk_buff *skb, netdevice_t *dev, struct sock *sk){ struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; wanpipe_common_t *chan = dev->priv; /* * When we registered the protocol we saved the socket in the data * field for just this event. */ skb->dev = dev; sll->sll_family = AF_WANPIPE; sll->sll_hatype = dev->type; sll->sll_protocol = skb->protocol; sll->sll_pkttype = skb->pkt_type; sll->sll_ifindex = dev->ifindex; sll->sll_halen = 0; if (dev->hard_header_parse) sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); /* * WAN_PACKET_DATA : Data which should be passed up the receive queue. * WAN_PACKET_ASYC : Asynchronous data like place call, which should * be passed up the listening sock. * WAN_PACKET_ERR : Asynchronous data like clear call or restart * which should go into an error queue. */ switch (skb->pkt_type){ case WAN_PACKET_DATA: if (sock_queue_rcv_skb(sk,skb)<0){ return -ENOMEM; } break; case WAN_PACKET_CMD: sk->state = chan->state; /* Bug fix: update Mar6. * Do not set the sock lcn number here, since * cmd is not guaranteed to be executed on the * board, thus Lcn could be wrong */ sk->data_ready(sk,skb->len); kfree_skb(skb); break; case WAN_PACKET_ERR: sk->state = chan->state; if (sock_queue_err_skb(sk,skb)<0){ return -ENOMEM; } break; default: printk(KERN_INFO "wansock: BH Illegal Packet Type Dropping\n"); kfree_skb(skb); break; }//??????????????????????// if (sk->state == WANSOCK_DISCONNECTED){// if (sk->zapped){// //printk(KERN_INFO "wansock: Disconnected, killing early\n");// wanpipe_unlink_driver(sk);// sk->bound_dev_if = 0;// }// } return 0;}/*============================================================ * wanpipe_listen_rcv * * Wanpipe LISTEN socket bottom half handler. This function * is called by the WANPIPE device drivers to queue an * incomming call into the socket listening queue. * Once the packet is queued, the waiting accept() process * is woken up. * * During socket bind, this function is bounded into * WANPIPE driver private. * * IMPORTANT NOTE: * The accept call() is waiting for an skb packet * which contains a pointer to a device structure. * * When we do a bind to a device structre, we * bind a newly created socket into "chan->sk". Thus, * when accept receives the skb packet, it will know * from which dev it came form, and in turn it will know * the address of the new sock. * * NOTE: This function gets called from driver ISR. *===========================================================*/static int wanpipe_listen_rcv (struct sk_buff *skb, struct sock *sk){ struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; struct sock *newsk; netdevice_t *dev; sdla_t *card; mbox_cmd_t *mbox_ptr; wanpipe_common_t *chan; /* Find a free device, if none found, all svc's are busy */ card = (sdla_t*)sk->protinfo.af_wanpipe->card; if (!card){ printk(KERN_INFO "wansock: LISTEN ERROR, No Card\n"); return -ENODEV; } dev = wanpipe_find_free_dev(card); if (!dev){ printk(KERN_INFO "wansock: LISTEN ERROR, No Free Device\n"); return -ENODEV; } chan=dev->priv; chan->state = WANSOCK_CONNECTING; /* Allocate a new sock, which accept will bind * and pass up to the user */ if ((newsk = wanpipe_make_new(sk)) == NULL){ release_device(dev); return -ENOMEM; } /* Initialize the new sock structure */ newsk->bound_dev_if = dev->ifindex; newsk->protinfo.af_wanpipe->card = sk->protinfo.af_wanpipe->card; /* Insert the sock into the main wanpipe * sock list. */ atomic_inc(&wanpipe_socks_nr); /* Allocate and fill in the new Mail Box. Then * bind the mail box to the sock. It will be * used by the ioctl call to read call information * and to execute commands. */ if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) { wanpipe_kill_sock_irq (newsk); release_device(dev); return -ENOMEM; } memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); memcpy(mbox_ptr,skb->data,skb->len); /* Register the lcn on which incoming call came * from. Thus, if we have to clear it, we know * whic lcn to clear */ newsk->protinfo.af_wanpipe->lcn = mbox_ptr->cmd.lcn; newsk->protinfo.af_wanpipe->mbox = (void *)mbox_ptr; DBG_PRINTK(KERN_INFO "NEWSOCK : Device %s, bind to lcn %i\n", dev->name,mbox_ptr->cmd.lcn); chan->lcn = mbox_ptr->cmd.lcn; card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev; newsk->zapped=0; newsk->num = htons(X25_PROT); if (wanpipe_do_bind(newsk,dev,newsk->num)){ wanpipe_kill_sock_irq (newsk); release_device(dev); return -EINVAL; } newsk->state = WANSOCK_CONNECTING; /* Fill in the standard sock address info */ sll->sll_family = AF_WANPIPE; sll->sll_hatype = dev->type; sll->sll_protocol = skb->protocol; sll->sll_pkttype = skb->pkt_type; sll->sll_ifindex = dev->ifindex; sll->sll_halen = 0; skb->dev = dev; sk->ack_backlog++; /* We must do this manually, since the sock_queue_rcv_skb() * function sets the skb->dev to NULL. However, we use * the dev field in the accept function.*/ if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf){ wanpipe_unlink_driver(newsk); wanpipe_kill_sock_irq (newsk); --sk->ack_backlog; return -ENOMEM; } skb_set_owner_r(skb, sk); skb_queue_tail(&sk->receive_queue, skb); sk->data_ready(sk,skb->len); return 0;}/*============================================================ * wanpipe_make_new * * Create a new sock, and allocate a wanpipe private * structure to it. Also, copy the important data * from the original sock to the new sock. * * This function is used by wanpipe_listen_rcv() listen * bottom half handler. A copy of the listening sock * is created using this function. * *===========================================================*/static struct sock *wanpipe_make_new(struct sock *osk){ struct sock *sk; if (osk->type != SOCK_RAW) return NULL; if ((sk = wanpipe_alloc_socket()) == NULL) return NULL; sk->type = osk->type; sk->socket = osk->socket; sk->priority = osk->priority; sk->protocol = osk->protocol; sk->num = osk->num; sk->rcvbuf = osk->rcvbuf; sk->sndbuf = osk->sndbuf; sk->debug = osk->debug; sk->state = WANSOCK_CONNECTING; sk->sleep = osk->sleep; return sk;}/*============================================================ * wanpipe_make_new * * Allocate memory for the a new sock, and sock * private data. * * Increment the module use count. * * This function is used by wanpipe_create() and * wanpipe_make_new() functions. * *===========================================================*/static struct sock *wanpipe_alloc_socket(void){ struct sock *sk; struct wanpipe_opt *wan_opt; if ((sk = sk_alloc(PF_WANPIPE, GFP_ATOMIC, 1)) == NULL) return NULL; if ((wan_opt = kmalloc(sizeof(struct wanpipe_opt), GFP_ATOMIC)) == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -