📄 af_wanpipe.c
字号:
set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { if (*skp == sk) { *skp = sk->next; __sock_put(sk); break; } } 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->state_change(sk); /* It is useless. Just for sanity. */ sock->sk = NULL; sk->socket = NULL; sk->dead = 1; /* Purge queues */#ifdef LINUX_2_4 skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sk->write_queue); skb_queue_purge(&sk->error_queue);#else while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ kfree_skb(skb); } while ((skb=skb_dequeue(&sk->error_queue))!=NULL){ kfree_skb(skb); } while ((skb=skb_dequeue(&sk->write_queue))!=NULL){ kfree_skb(skb); }#endif if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { del_timer(&sk->timer); printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n", atomic_read(&sk->rmem_alloc),atomic_read(&sk->wmem_alloc)); sk->timer.data=(unsigned long)sk; sk->timer.expires=jiffies+HZ; sk->timer.function=wanpipe_destroy_timer; add_timer(&sk->timer); return 0; } if (sk->protinfo.af_wanpipe){ kfree(sk->protinfo.af_wanpipe); sk->protinfo.af_wanpipe=NULL; } #ifdef LINUX_2_4 if (atomic_read(&sk->refcnt) != 1){ DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:release.\n", atomic_read(&sk->refcnt)); atomic_set(&sk->refcnt,1); } sock_put(sk); #else sk_free(sk); #endif atomic_dec(&wanpipe_socks_nr); MOD_DEC_USE_COUNT; 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->state != WANSOCK_CONNECTED) return; if (!atomic_read(&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){ struct sk_buff *skb=NULL; struct sock *deadsk=NULL; if (sk->state == WANSOCK_LISTEN || sk->state == WANSOCK_BIND_LISTEN){ while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ if ((deadsk = get_newsk_from_skb(skb))){ DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n"); deadsk->dead=1; start_cleanup_timer(deadsk); } kfree_skb(skb); } if (sk->zapped) wanpipe_unlink_card(sk); }else{ if (sk->zapped) wanpipe_unlink_driver(sk); } sk->state = WANSOCK_DISCONNECTED; sk->bound_dev_if = 0; sk->zapped=0; if (sk->protinfo.af_wanpipe){ if (sk->protinfo.af_wanpipe->mbox){ kfree(sk->protinfo.af_wanpipe->mbox); sk->protinfo.af_wanpipe->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->timer); sk->timer.data = (unsigned long)sk; sk->timer.expires = jiffies + HZ; sk->timer.function = wanpipe_kill_sock_timer; add_timer(&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;#ifndef LINUX_2_4 struct sk_buff *skb;#endif struct sock **skp; if (!sk) return; /* This functin can be called from interrupt. We must use * appropriate locks */ if (test_bit(1,&wanpipe_tx_critical)){ sk->timer.expires=jiffies+10; add_timer(&sk->timer); return; } write_lock(&wanpipe_sklist_lock); for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { if (*skp == sk) { *skp = sk->next; __sock_put(sk); break; } } write_unlock(&wanpipe_sklist_lock); if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED){ netdevice_t *dev = dev_get_by_index(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->socket = NULL; /* Purge queues */#ifdef LINUX_2_4 skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sk->write_queue); skb_queue_purge(&sk->error_queue);#else while ((skb=skb_dequeue(&sk->receive_queue)) != NULL){ kfree_skb(skb); } while ((skb=skb_dequeue(&sk->write_queue)) != NULL) { kfree_skb(skb); } while ((skb=skb_dequeue(&sk->error_queue)) != NULL){ kfree_skb(skb); }#endif if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { del_timer(&sk->timer); printk(KERN_INFO "wansock: Killing SOCK in Timer\n"); sk->timer.data=(unsigned long)sk; sk->timer.expires=jiffies+HZ; sk->timer.function=wanpipe_destroy_timer; add_timer(&sk->timer); return; } if (sk->protinfo.af_wanpipe){ kfree(sk->protinfo.af_wanpipe); sk->protinfo.af_wanpipe=NULL; } #ifdef LINUX_2_4 if (atomic_read(&sk->refcnt) != 1){ atomic_set(&sk->refcnt,1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", atomic_read(&sk->refcnt)); } sock_put(sk); #else sk_free(sk); #endif atomic_dec(&wanpipe_socks_nr); MOD_DEC_USE_COUNT; return;}static void wanpipe_kill_sock_accept (struct sock *sk){ struct sock **skp; if (!sk) return; /* This functin can be called from interrupt. We must use * appropriate locks */ write_lock(&wanpipe_sklist_lock); for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { if (*skp == sk) { *skp = sk->next; __sock_put(sk); break; } } write_unlock(&wanpipe_sklist_lock); sk->socket = NULL; if (sk->protinfo.af_wanpipe){ kfree(sk->protinfo.af_wanpipe); sk->protinfo.af_wanpipe=NULL; } #ifdef LINUX_2_4 if (atomic_read(&sk->refcnt) != 1){ atomic_set(&sk->refcnt,1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", atomic_read(&sk->refcnt)); } sock_put(sk); #else sk_free(sk); #endif atomic_dec(&wanpipe_socks_nr); MOD_DEC_USE_COUNT; return;}static void wanpipe_kill_sock_irq (struct sock *sk){ if (!sk) return; sk->socket = NULL; if (sk->protinfo.af_wanpipe){ kfree(sk->protinfo.af_wanpipe); sk->protinfo.af_wanpipe=NULL; } #ifdef LINUX_2_4 if (atomic_read(&sk->refcnt) != 1){ atomic_set(&sk->refcnt,1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:listen.\n", atomic_read(&sk->refcnt)); } sock_put(sk); #else sk_free(sk); #endif atomic_dec(&wanpipe_socks_nr); MOD_DEC_USE_COUNT; return;}/*============================================================ * 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, netdevice_t *dev, int protocol){ wanpipe_common_t *chan=NULL; int err=0; if (sk->zapped){ err = -EALREADY; goto bind_unlock_exit; } sk->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->state = chan->state; if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED && sk->state != WANSOCK_CONNECTING){ DBG_PRINTK(KERN_INFO "wansock: Binding to Device not DISCONNECTED %i\n", sk->state); release_device(dev); err = -EAGAIN; goto bind_unlock_exit; } wanpipe_link_driver(dev,sk); sk->bound_dev_if = dev->ifindex; /* X25 Specific option */ if (sk->num == htons(X25_PROT)) sk->protinfo.af_wanpipe->svc = chan->svc; } else { sk->err = ENETDOWN; 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; netdevice_t *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{ sk->protinfo.af_wanpipe->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) sk->num = sll->sll_protocol; 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 */ strncpy(name,sll->sll_device,14); name[14]=0;#ifdef LINUX_2_4 dev = dev_get_by_name(name);#else dev = dev_get(name);#endif 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 ? : sk->num);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -