📄 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.* ============================================================================* Mar 15, 2002 Arnaldo C. Melo o Use wp_sk()->num, as it isnt anymore in sock* 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/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 /* 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->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->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->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 until 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 * successfully queued. If the socket queue is full, * protocol flow control is used by the driver, if any, * to slow down the traffic until 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. */HLIST_HEAD(wanpipe_sklist);static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED;atomic_t wanpipe_socks_nr;static unsigned long wanpipe_tx_critical;#if 0/* Private wanpipe socket structures. */struct wanpipe_opt{ void *mbox; /* Mail box */ void *card; /* Card bouded to */ struct net_device *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;extern struct proto_ops wanpipe_ops;static unsigned long find_free_critical;static void wanpipe_unlink_driver(struct sock *sk);static void wanpipe_link_driver(struct net_device *dev, 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(struct net_device *dev, sdla_t *card);struct net_device *wanpipe_find_free_dev(sdla_t *card);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(struct net_device *dev);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(struct net_device *dev);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 *sk, struct net_device *dev, int protocol);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 * incoming 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, struct net_device *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->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->sk_data_ready(sk, skb->len); kfree_skb(skb); break; case WAN_PACKET_ERR: sk->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->sk_state == WANSOCK_DISCONNECTED){// if (sk->sk_zapped) {// //printk(KERN_INFO "wansock: Disconnected, killing early\n");// wanpipe_unlink_driver(sk);// 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 * incoming 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){ wanpipe_opt *wp = wp_sk(sk), *newwp; struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb; struct sock *newsk; struct net_device *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*)wp->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->sk_bound_dev_if = dev->ifindex; newwp = wp_sk(newsk); newwp->card = wp->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 * which lcn to clear */ newwp->lcn = mbox_ptr->cmd.lcn; newwp->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->sk_zapped = 0; newwp->num = htons(X25_PROT); if (wanpipe_do_bind(newsk, dev, newwp->num)) { wanpipe_kill_sock_irq (newsk); release_device(dev); return -EINVAL; } newsk->sk_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->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->sk_rmem_alloc) + skb->truesize >= (unsigned)sk->sk_rcvbuf) { wanpipe_unlink_driver(newsk); wanpipe_kill_sock_irq (newsk); --sk->sk_ack_backlog; return -ENOMEM; } skb_set_owner_r(skb, sk); skb_queue_tail(&sk->sk_receive_queue, skb); sk->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->sk_type != SOCK_RAW) return NULL; if ((sk = wanpipe_alloc_socket()) == NULL) return NULL; sk->sk_type = osk->sk_type; sk->sk_socket = osk->sk_socket; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; wp_sk(sk)->num = wp_sk(osk)->num; sk->sk_rcvbuf = osk->sk_rcvbuf; sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_debug = osk->sk_debug; sk->sk_state = WANSOCK_CONNECTING; sk->sk_sleep = osk->sk_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)) == NULL) return NULL; if ((wan_opt = kmalloc(sizeof(struct wanpipe_opt), GFP_ATOMIC)) == NULL) { sk_free(sk); return NULL; } memset(wan_opt, 0x00, sizeof(struct wanpipe_opt));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -