📄 af_wanpipe.c
字号:
wp_sk(sk) = wan_opt; /* Use timer to send data to the driver. This will act * as a BH handler for sendmsg functions */ init_timer(&wan_opt->tx_timer); wan_opt->tx_timer.data = (unsigned long)sk; wan_opt->tx_timer.function = wanpipe_delayed_transmit; sock_init_data(NULL, sk); return sk;}/*============================================================ * wanpipe_sendmsg * * This function implements a sendto() system call, * for AF_WANPIPE socket family. * During socket bind() sk->sk_bound_dev_if is initialized * to a correct network device. This number is used * to find a network device to which the packet should * be passed to. * * Each packet is queued into sk->sk_write_queue and * delayed transmit bottom half handler is marked for * execution. * * A socket must be in WANSOCK_CONNECTED state before * a packet is queued into sk->sk_write_queue. *===========================================================*/static int wanpipe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int len){ wanpipe_opt *wp; struct sock *sk = sock->sk; struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name; struct sk_buff *skb; struct net_device *dev; unsigned short proto; unsigned char *addr; int ifindex, err, reserve = 0; if (!sk->sk_zapped) return -ENETDOWN; if (sk->sk_state != WANSOCK_CONNECTED) return -ENOTCONN; if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) return(-EINVAL); /* it was <=, now one can send * zero length packets */ if (len < sizeof(x25api_hdr_t)) return -EINVAL; wp = wp_sk(sk); if (saddr == NULL) { ifindex = sk->sk_bound_dev_if; proto = wp->num; addr = NULL; }else{ if (msg->msg_namelen < sizeof(struct wan_sockaddr_ll)){ return -EINVAL; } ifindex = sk->sk_bound_dev_if; proto = saddr->sll_protocol; addr = saddr->sll_addr; } dev = dev_get_by_index(ifindex); if (dev == NULL){ printk(KERN_INFO "wansock: Send failed, dev index: %i\n",ifindex); return -ENXIO; } dev_put(dev); if (sock->type == SOCK_RAW) reserve = dev->hard_header_len; if (len > dev->mtu+reserve){ return -EMSGSIZE; } skb = sock_alloc_send_skb(sk, len + LL_RESERVED_SPACE(dev), msg->msg_flags & MSG_DONTWAIT, &err); if (skb==NULL){ goto out_unlock; } skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb->nh.raw = skb->data; /* Returns -EFAULT on error */ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); if (err){ goto out_free; } if (dev->hard_header) { int res; err = -EINVAL; res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); if (res<0){ goto out_free; } } skb->protocol = proto; skb->dev = dev; skb->priority = sk->sk_priority; skb->pkt_type = WAN_PACKET_DATA; err = -ENETDOWN; if (!(dev->flags & IFF_UP)) goto out_free; if (atomic_read(&sk->sk_wmem_alloc) + skb->truesize > (unsigned int)sk->sk_sndbuf){ kfree_skb(skb); return -ENOBUFS; } skb_queue_tail(&sk->sk_write_queue,skb); atomic_inc(&wp->packet_sent); if (!(test_and_set_bit(0, &wp->timer))) mod_timer(&wp->tx_timer, jiffies + 1); return(len);out_free: kfree_skb(skb);out_unlock: return err;}/*============================================================ * wanpipe_delayed_tarnsmit * * Transmit bottom half handler. It dequeues packets * from sk->sk_write_queue and passes them to the * driver. If the driver is busy, the packet is * re-enqueued. * * Packet Sent counter is decremented on successful * transmission. *===========================================================*/static void wanpipe_delayed_transmit (unsigned long data){ struct sock *sk=(struct sock *)data; struct sk_buff *skb; wanpipe_opt *wp = wp_sk(sk); struct net_device *dev = wp->dev; sdla_t *card = (sdla_t*)wp->card; if (!card || !dev){ clear_bit(0, &wp->timer); DBG_PRINTK(KERN_INFO "wansock: Transmit delay, no dev or card\n"); return; } if (sk->sk_state != WANSOCK_CONNECTED || !sk->sk_zapped) { clear_bit(0, &wp->timer); DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n"); return; } /* If driver is executing command, we must offload * the board by not sending data. Otherwise a * pending command will never get a free buffer * to execute */ if (atomic_read(&card->u.x.command_busy)){ wp->tx_timer.expires = jiffies + SLOW_BACKOFF; add_timer(&wp->tx_timer); DBG_PRINTK(KERN_INFO "wansock: Tx Timer, command bys BACKOFF\n"); return; } if (test_and_set_bit(0,&wanpipe_tx_critical)){ printk(KERN_INFO "WanSock: Tx timer critical %s\n",dev->name); wp->tx_timer.expires = jiffies + SLOW_BACKOFF; add_timer(&wp->tx_timer); return; } /* Check for a packet in the fifo and send */ if ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL){ if (dev->hard_start_xmit(skb, dev) != 0){ /* Driver failed to transmit, re-enqueue * the packet and retry again later */ skb_queue_head(&sk->sk_write_queue,skb); clear_bit(0,&wanpipe_tx_critical); return; }else{ /* Packet Sent successful. Check for more packets * if more packets, re-trigger the transmit routine * other wise exit */ atomic_dec(&wp->packet_sent); if (skb_peek(&sk->sk_write_queue) == NULL) { /* If there is nothing to send, kick * the poll routine, which will trigger * the application to send more data */ sk->sk_data_ready(sk, 0); clear_bit(0, &wp->timer); }else{ /* Reschedule as fast as possible */ wp->tx_timer.expires = jiffies + 1; add_timer(&wp->tx_timer); } } } clear_bit(0,&wanpipe_tx_critical);}/*============================================================ * execute_command * * Execute x25api commands. The atomic variable * chan->command is used to indicate to the driver that * command is pending for execution. The acutal command * structure is placed into a sock mbox structure * (wp_sk(sk)->mbox). * * The sock private structure, mbox is * used as shared memory between sock and the driver. * Driver uses the sock mbox to execute the command * and return the result. * * For all command except PLACE CALL, the function * waits for the result. PLACE CALL can be ether * blocking or nonblocking. The user sets this option * via ioctl call. *===========================================================*/static int execute_command(struct sock *sk, unsigned char cmd, unsigned int flags){ wanpipe_opt *wp = wp_sk(sk); struct net_device *dev; wanpipe_common_t *chan=NULL; int err=0; DECLARE_WAITQUEUE(wait, current); dev = dev_get_by_index(sk->sk_bound_dev_if); if (dev == NULL){ printk(KERN_INFO "wansock: Exec failed no dev %i\n", sk->sk_bound_dev_if); return -ENODEV; } dev_put(dev); if ((chan=dev->priv) == NULL){ printk(KERN_INFO "wansock: Exec cmd failed no priv area\n"); return -ENODEV; } if (atomic_read(&chan->command)){ printk(KERN_INFO "wansock: ERROR: Command already running %x, %s\n", atomic_read(&chan->command),dev->name); return -EINVAL; } if (!wp->mbox) { printk(KERN_INFO "wansock: In execute without MBOX\n"); return -EINVAL; } ((mbox_cmd_t*)wp->mbox)->cmd.command = cmd; ((mbox_cmd_t*)wp->mbox)->cmd.lcn = wp->lcn; ((mbox_cmd_t*)wp->mbox)->cmd.result = 0x7F; if (flags & O_NONBLOCK){ cmd |= 0x80; atomic_set(&chan->command, cmd); }else{ atomic_set(&chan->command, cmd); } add_wait_queue(sk->sk_sleep,&wait); current->state = TASK_INTERRUPTIBLE; for (;;){ if (((mbox_cmd_t*)wp->mbox)->cmd.result != 0x7F) { err = 0; break; } if (signal_pending(current)) { err = -ERESTARTSYS; break; } schedule(); } current->state = TASK_RUNNING; remove_wait_queue(sk->sk_sleep,&wait); return err;}/*============================================================ * wanpipe_destroy_timer * * Used by wanpipe_release, to delay release of * the socket. *===========================================================*/static void wanpipe_destroy_timer(unsigned long data){ struct sock *sk=(struct sock *)data; wanpipe_opt *wp = wp_sk(sk); if ((!atomic_read(&sk->sk_wmem_alloc) && !atomic_read(&sk->sk_rmem_alloc)) || (++wp->force == 5)) { if (atomic_read(&sk->sk_wmem_alloc) || atomic_read(&sk->sk_rmem_alloc)) printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n"); kfree(wp); wp_sk(sk) = NULL; if (atomic_read(&sk->sk_refcnt) != 1) { atomic_set(&sk->sk_refcnt, 1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n", atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); return; } sk->sk_timer.expires = jiffies + 5 * HZ; add_timer(&sk->sk_timer); printk(KERN_INFO "wansock: packet sk destroy delayed\n");}/*============================================================ * wanpipe_unlink_driver * * When the socket is released, this function is * used to remove links that bind the sock and the * driver together. *===========================================================*/static void wanpipe_unlink_driver (struct sock *sk){ struct net_device *dev; wanpipe_common_t *chan=NULL; sk->sk_zapped = 0; sk->sk_state = WANSOCK_DISCONNECTED; wp_sk(sk)->dev = NULL; dev = dev_get_by_index(sk->sk_bound_dev_if); if (!dev){ printk(KERN_INFO "wansock: No dev on release\n"); return; } dev_put(dev); if ((chan = dev->priv) == NULL){ printk(KERN_INFO "wansock: No Priv Area on release\n"); return; } set_bit(0,&chan->common_critical); chan->sk=NULL; chan->func=NULL; chan->mbox=NULL; chan->tx_timer=NULL; clear_bit(0,&chan->common_critical); release_device(dev); return;}/*============================================================ * wanpipe_link_driver * * Upon successful bind(), sock is linked to a driver * by binding in the wanpipe_rcv() bottom half handler * to the driver function pointer, as well as sock and * sock mailbox addresses. This way driver can pass * data up the socket. *===========================================================*/static void wanpipe_link_driver(struct net_device *dev, struct sock *sk){ wanpipe_opt *wp = wp_sk(sk); wanpipe_common_t *chan = dev->priv; if (!chan) return; set_bit(0,&chan->common_critical); chan->sk=sk; chan->func=wanpipe_rcv; chan->mbox = wp->mbox; chan->tx_timer = &wp->tx_timer; wp->dev = dev; sk->sk_zapped = 1; clear_bit(0,&chan->common_critical);}/*============================================================ * release_device * * During sock release, clear a critical bit, which * marks the device a being taken. *===========================================================*/static void release_device(struct net_device *dev){ wanpipe_common_t *chan=dev->priv; clear_bit(0,(void*)&chan->rw_bind);}/*============================================================ * wanpipe_release * * Close a PACKET socket. This is fairly simple. We * immediately go to 'closed' state and remove our * protocol entry in the device list. *===========================================================*/static int wanpipe_release(struct socket *sock){ wanpipe_opt *wp; struct sock *sk = sock->sk; if (!sk) return 0; wp = wp_sk(sk); check_write_queue(sk); /* Kill the tx timer, if we don't kill it now, the timer * will run after we kill the sock. Timer code will * try to access the sock which has been killed and cause * kernel panic */ del_timer(&wp->tx_timer); /* * Unhook packet receive handler. */ if (wp->num == htons(X25_PROT) && sk->sk_state != WANSOCK_DISCONNECTED && sk->sk_zapped) { struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); wanpipe_common_t *chan; if (dev){ chan=dev->priv; atomic_set(&chan->disconnect,1); DBG_PRINTK(KERN_INFO "wansock: Sending Clear Indication %i\n", sk->sk_state); dev_put(dev); } } set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); release_driver(sk); /* * Now the socket is dead. No more input will appear. */ sk->sk_state_change(sk); /* It is useless. Just for sanity. */ sock->sk = NULL; sk->sk_socket = NULL; sock_set_flag(sk, SOCK_DEAD); /* Purge queues */ skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&sk->sk_error_queue); if (atomic_read(&sk->sk_rmem_alloc) || atomic_read(&sk->sk_wmem_alloc)) { del_timer(&sk->sk_timer); printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -