📄 af_wanpipe.c
字号:
atomic_read(&sk->sk_rmem_alloc), atomic_read(&sk->sk_wmem_alloc)); sk->sk_timer.data = (unsigned long)sk; sk->sk_timer.expires = jiffies + HZ; sk->sk_timer.function = wanpipe_destroy_timer; add_timer(&sk->sk_timer); return 0; } kfree(wp); wp_sk(sk) = NULL; if (atomic_read(&sk->sk_refcnt) != 1) { DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:release.\n", atomic_read(&sk->sk_refcnt)); atomic_set(&sk->sk_refcnt, 1); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); return 0;}/*============================================================ * check_write_queue * * During sock shutdown, if the sock state is * WANSOCK_CONNECTED and there is transmit data * pending. Wait until data is released * before proceeding. *===========================================================*/static void check_write_queue(struct sock *sk){ if (sk->sk_state != WANSOCK_CONNECTED) return; if (!atomic_read(&sk->sk_wmem_alloc)) return; printk(KERN_INFO "wansock: MAJOR ERROR, Data lost on sock release !!!\n");}/*============================================================ * release_driver * * This function is called during sock shutdown, to * release any resources and links that bind the sock * to the driver. It also changes the state of the * sock to WANSOCK_DISCONNECTED *===========================================================*/static void release_driver(struct sock *sk){ wanpipe_opt *wp; struct sk_buff *skb=NULL; struct sock *deadsk=NULL; if (sk->sk_state == WANSOCK_LISTEN || sk->sk_state == WANSOCK_BIND_LISTEN) { while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { if ((deadsk = get_newsk_from_skb(skb))){ DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n"); sock_set_flag(deadsk, SOCK_DEAD); start_cleanup_timer(deadsk); } kfree_skb(skb); } if (sk->sk_zapped) wanpipe_unlink_card(sk); }else{ if (sk->sk_zapped) wanpipe_unlink_driver(sk); } sk->sk_state = WANSOCK_DISCONNECTED; sk->sk_bound_dev_if = 0; sk->sk_zapped = 0; wp = wp_sk(sk); if (wp && wp->mbox) { kfree(wp->mbox); wp->mbox = NULL; }}/*============================================================ * start_cleanup_timer * * If new incoming call's are pending but the socket * is being released, start the timer which will * envoke the kill routines for pending socks. *===========================================================*/static void start_cleanup_timer (struct sock *sk){ del_timer(&sk->sk_timer); sk->sk_timer.data = (unsigned long)sk; sk->sk_timer.expires = jiffies + HZ; sk->sk_timer.function = wanpipe_kill_sock_timer; add_timer(&sk->sk_timer);}/*============================================================ * wanpipe_kill_sock * * This is a function which performs actual killing * of the sock. It releases socket resources, * and unlinks the sock from the driver. *===========================================================*/static void wanpipe_kill_sock_timer (unsigned long data){ struct sock *sk = (struct sock *)data; struct sock **skp; if (!sk) return; /* This function can be called from interrupt. We must use * appropriate locks */ if (test_bit(1,&wanpipe_tx_critical)){ sk->sk_timer.expires = jiffies + 10; add_timer(&sk->sk_timer); return; } write_lock(&wanpipe_sklist_lock); sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); if (wp_sk(sk)->num == htons(X25_PROT) && sk->sk_state != WANSOCK_DISCONNECTED) { 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); dev_put(dev); } } release_driver(sk); sk->sk_socket = NULL; /* 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 SOCK in Timer\n"); sk->sk_timer.data = (unsigned long)sk; sk->sk_timer.expires = jiffies + HZ; sk->sk_timer.function = wanpipe_destroy_timer; add_timer(&sk->sk_timer); return; } if (wp_sk(sk)) { kfree(wp_sk(sk)); 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 ! :timer.\n", atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); return;}static void wanpipe_kill_sock_accept (struct sock *sk){ struct sock **skp; if (!sk) return; /* This function can be called from interrupt. We must use * appropriate locks */ write_lock(&wanpipe_sklist_lock); sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); sk->sk_socket = NULL; if (wp_sk(sk)) { kfree(wp_sk(sk)); 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 ! :timer.\n", atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); return;}static void wanpipe_kill_sock_irq (struct sock *sk){ if (!sk) return; sk->sk_socket = NULL; if (wp_sk(sk)) { kfree(wp_sk(sk)); 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 !:listen.\n", atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr);}/*============================================================ * wanpipe_do_bind * * Bottom half of the binding system call. * Once the wanpipe_bind() function checks the * legality of the call, this function binds the * sock to the driver. *===========================================================*/static int wanpipe_do_bind(struct sock *sk, struct net_device *dev, int protocol){ wanpipe_opt *wp = wp_sk(sk); wanpipe_common_t *chan=NULL; int err=0; if (sk->sk_zapped) { err = -EALREADY; goto bind_unlock_exit; } wp->num = protocol; if (protocol == 0){ release_device(dev); err = -EINVAL; goto bind_unlock_exit; } if (dev) { if (dev->flags&IFF_UP) { chan=dev->priv; sk->sk_state = chan->state; if (wp->num == htons(X25_PROT) && sk->sk_state != WANSOCK_DISCONNECTED && sk->sk_state != WANSOCK_CONNECTING) { DBG_PRINTK(KERN_INFO "wansock: Binding to Device not DISCONNECTED %i\n", sk->sk_state); release_device(dev); err = -EAGAIN; goto bind_unlock_exit; } wanpipe_link_driver(dev,sk); sk->sk_bound_dev_if = dev->ifindex; /* X25 Specific option */ if (wp->num == htons(X25_PROT)) wp_sk(sk)->svc = chan->svc; } else { sk->sk_err = ENETDOWN; sk->sk_error_report(sk); release_device(dev); err = -EINVAL; } } else { err = -ENODEV; }bind_unlock_exit: /* FIXME where is this lock */ return err;}/*============================================================ * wanpipe_bind * * BIND() System call, which is bound to the AF_WANPIPE * operations structure. It checks for correct wanpipe * card name, and cross references interface names with * the card names. Thus, interface name must belong to * the actual card. *===========================================================*/static int wanpipe_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){ struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; struct sock *sk=sock->sk; wanpipe_opt *wp = wp_sk(sk); struct net_device *dev = NULL; sdla_t *card=NULL; char name[15]; /* * Check legality */ if (addr_len < sizeof(struct wan_sockaddr_ll)){ printk(KERN_INFO "wansock: Address length error\n"); return -EINVAL; } if (sll->sll_family != AF_WANPIPE){ printk(KERN_INFO "wansock: Illegal family name specified.\n"); return -EINVAL; } card = wanpipe_find_card (sll->sll_card); if (!card){ printk(KERN_INFO "wansock: Wanpipe card not found: %s\n",sll->sll_card); return -ENODEV; }else{ wp_sk(sk)->card = (void *)card; } if (!strcmp(sll->sll_device,"svc_listen")){ /* Bind a sock to a card structure for listening */ int err=0; /* This is x25 specific area if protocol doesn't * match, return error */ if (sll->sll_protocol != htons(X25_PROT)) return -EINVAL; err= wanpipe_link_card (sk); if (err < 0) return err; if (sll->sll_protocol) wp->num = sll->sll_protocol; sk->sk_state = WANSOCK_BIND_LISTEN; return 0; }else if (!strcmp(sll->sll_device,"svc_connect")){ /* This is x25 specific area if protocol doesn't * match, return error */ if (sll->sll_protocol != htons(X25_PROT)) return -EINVAL; /* Find a free device */ dev = wanpipe_find_free_dev(card); if (dev == NULL){ DBG_PRINTK(KERN_INFO "wansock: No free network devices for card %s\n", card->devname); return -EINVAL; } }else{ /* Bind a socket to a interface name * This is used by PVC mostly */ strlcpy(name,sll->sll_device,sizeof(name)); dev = dev_get_by_name(name); if (dev == NULL){ printk(KERN_INFO "wansock: Failed to get Dev from name: %s,\n", name); return -ENODEV; } dev_put(dev); if (check_dev(dev, card)){ printk(KERN_INFO "wansock: Device %s, doesn't belong to card %s\n", dev->name, card->devname); return -EINVAL; } if (get_atomic_device (dev)) return -EINVAL; } return wanpipe_do_bind(sk, dev, sll->sll_protocol ? : wp->num);}/*============================================================ * get_atomic_device * * Sets a bit atomically which indicates that * the interface is taken. This avoids race conditions. *===========================================================*/static inline int get_atomic_device(struct net_device *dev){ wanpipe_common_t *chan = dev->priv; if (!test_and_set_bit(0,(void *)&chan->rw_bind)){ return 0; } return 1;}/*============================================================ * check_dev * * Check that device name belongs to a particular card. *===========================================================*/static int check_dev(struct net_device *dev, sdla_t *card){ struct net_device* tmp_dev; for (tmp_dev = card->wandev.dev; tmp_dev; tmp_dev = *((struct net_device **)tmp_dev->priv)) { if (tmp_dev->ifindex == dev->ifindex){ return 0; } } return 1;}/*============================================================ * wanpipe_find_free_dev * * Find a free network interface. If found set atomic * bit indicating that the interface is taken. * X25API Specific. *===========================================================*/struct net_device *wanpipe_find_free_dev(sdla_t *card){ struct net_device* dev; volatile wanpipe_common_t *chan; if (test_and_set_bit(0,&find_free_critical)){ printk(KERN_INFO "CRITICAL in Find Free\n"); } for (dev = card->wandev.dev; dev; dev = *((struct net_device **)dev->priv)) { chan = dev->priv; if (!chan) continue; if (chan->usedby == API && chan->svc){ if (!get_atomic_device (dev)){ if (chan->state != WANSOCK_DISCONNECTED){ release_device(dev); }else{ clear_bit(0,&find_free_critical); return dev; } } } } clear_bit(0,&find_free_critical); return NULL;}/*============================================================ * wanpipe_create * * SOCKET() System call. It allocates a sock structure * and adds the socket to the wanpipe_sk_list. * Crates AF_WANPIPE socket. *===========================================================*/static int wanpipe_create(struct socket *sock, int protocol){ struct sock *sk; //FIXME: This checks for root user, SECURITY ? //if (!capable(CAP_NET_RAW)) // return -EPERM; if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; sock->state = SS_UNCONNECTED; if ((sk = wanpipe_alloc_socket()) == NULL) return -ENOBUFS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -