📄 af_wanpipe.c
字号:
}/*============================================================ * get_atomic_device * * Sets a bit atomically which indicates that * the interface is taken. This avoids race conditions. *===========================================================*/static inline int get_atomic_device (netdevice_t *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 (netdevice_t *dev, sdla_t *card){ netdevice_t* tmp_dev; for (tmp_dev = card->wandev.dev; tmp_dev; tmp_dev=*((netdevice_t**)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. *===========================================================*/netdevice_t * wanpipe_find_free_dev (sdla_t *card){ netdevice_t* 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=*((netdevice_t**)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; sk->reuse = 1; sock->ops = &wanpipe_ops; sock_init_data(sock,sk); sk->zapped=0; sk->family = PF_WANPIPE; sk->num = protocol; sk->state = WANSOCK_DISCONNECTED; sk->ack_backlog = 0; sk->bound_dev_if=0; atomic_inc(&wanpipe_socks_nr); /* We must disable interrupts because the ISR * can also change the list */ set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); sk->next = wanpipe_sklist; wanpipe_sklist = sk; sock_hold(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); return(0);}/*============================================================ * wanpipe_recvmsg * * Pull a packet from our receive queue and hand it * to the user. If necessary we block. *===========================================================*/static int wanpipe_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sk_buff *skb; int copied, err=-ENOBUFS; /* * If the address length field is there to be filled in, we fill * it in now. */ msg->msg_namelen = sizeof(struct wan_sockaddr_ll); /* * Call the generic datagram receiver. This handles all sorts * of horrible races and re-entrancy so we can forget about it * in the protocol layers. * * Now it will return ENETDOWN, if device have just gone down, * but then it will block. */ if (flags & MSG_OOB){ skb=skb_dequeue(&sk->error_queue); }else{ skb=skb_recv_datagram(sk,flags,1,&err); } /* * An error occurred so return it. Because skb_recv_datagram() * handles the blocking we don't see and worry about blocking * retries. */ if(skb==NULL) goto out; /* * You lose any data beyond the buffer you gave. If it worries a * user program they can ask the device for its MTU anyway. */ copied = skb->len; if (copied > len) { copied=len; msg->msg_flags|=MSG_TRUNC; } wanpipe_wakeup_driver(sk); /* We can't use skb_copy_datagram here */ err = memcpy_toiovec(msg->msg_iov, skb->data, copied); if (err) goto out_free; #ifdef LINUX_2_1 sk->stamp=skb->stamp;#else sock_recv_timestamp(msg, sk, skb);#endif if (msg->msg_name) memcpy(msg->msg_name, skb->cb, msg->msg_namelen); /* * Free or return the buffer as appropriate. Again this * hides all the races and re-entrancy issues from us. */ err = (flags&MSG_TRUNC) ? skb->len : copied;out_free: skb_free_datagram(sk, skb);out: return err;}/*============================================================ * wanpipe_wakeup_driver * * If socket receive buffer is full and driver cannot * pass data up the sock, it sets a packet_block flag. * This function check that flag and if sock receive * queue has room it kicks the driver BH handler. * * This way, driver doesn't have to poll the sock * receive queue. *===========================================================*/static void wanpipe_wakeup_driver(struct sock *sk){ netdevice_t *dev=NULL; wanpipe_common_t *chan=NULL; dev = dev_get_by_index(sk->bound_dev_if); if (!dev) return; dev_put(dev); if ((chan = dev->priv) == NULL) return; if (atomic_read(&chan->receive_block)){ if (atomic_read(&sk->rmem_alloc) < ((unsigned)sk->rcvbuf*0.9) ){ printk(KERN_INFO "wansock: Queuing task for wanpipe\n"); atomic_set(&chan->receive_block,0); wanpipe_queue_tq(&chan->wanpipe_task); wanpipe_mark_bh(); } } } /*============================================================ * wanpipe_getname * * I don't know what to do with this yet. * User can use this function to get sock address * information. Not very useful for Sangoma's purposes. *===========================================================*/static int wanpipe_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer){ netdevice_t *dev; struct sock *sk = sock->sk; struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; sll->sll_family = AF_WANPIPE; sll->sll_ifindex = sk->bound_dev_if; sll->sll_protocol = sk->num; dev = dev_get_by_index(sk->bound_dev_if); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len); } else { sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ sll->sll_halen = 0; } *uaddr_len = sizeof(*sll); dev_put(dev); return 0;}/*============================================================ * wanpipe_notifier * * If driver turns off network interface, this function * will be envoked. Currently I treate it as a * call disconnect. More thought should go into this * function. * * FIXME: More thought should go into this function. * *===========================================================*/static int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void *data){ struct sock *sk; netdevice_t *dev = (netdevice_t*)data; struct wanpipe_opt *po; for (sk = wanpipe_sklist; sk; sk = sk->next) { if ((po = sk->protinfo.af_wanpipe)==NULL) continue; if (dev == NULL) continue; switch (msg) { case NETDEV_DOWN: case NETDEV_UNREGISTER: if (dev->ifindex == sk->bound_dev_if) { printk(KERN_INFO "wansock: Device down %s\n",dev->name); if (sk->zapped){ wanpipe_unlink_driver(sk); sk->err = ENETDOWN; sk->error_report(sk); } if (msg == NETDEV_UNREGISTER) { printk(KERN_INFO "wansock: Unregistering Device: %s\n", dev->name); wanpipe_unlink_driver(sk); sk->bound_dev_if = 0; } } break; case NETDEV_UP: if (dev->ifindex == sk->bound_dev_if && sk->num && !sk->zapped) { printk(KERN_INFO "wansock: Registering Device: %s\n", dev->name); wanpipe_link_driver(dev,sk); } break; } } return NOTIFY_DONE;}/*============================================================ * wanpipe_ioctl * * Execute a user commands, and set socket options. * * FIXME: More thought should go into this function. * *===========================================================*/static int wanpipe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; int err; int pid; switch(cmd) { case FIOSETOWN: case SIOCSPGRP: err = get_user(pid, (int *) arg); if (err) return err; if (current->pid != pid && current->pgrp != -pid && !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); case FIOGETOWN: case SIOCGPGRP: return put_user(sk->proc, (int *)arg); case SIOCGSTAMP: if(sk->stamp.tv_sec==0) return -ENOENT; err = -EFAULT; if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) err = 0; return err; case SIOC_WANPIPE_CHECK_TX: return atomic_read(&sk->wmem_alloc); case SIOC_WANPIPE_SOCK_STATE: if (sk->state == WANSOCK_CONNECTED) return 0; return 1; case SIOC_WANPIPE_GET_CALL_DATA: return get_ioctl_cmd (sk,(void*)arg); case SIOC_WANPIPE_SET_CALL_DATA: return set_ioctl_cmd (sk,(void*)arg); case SIOC_WANPIPE_ACCEPT_CALL: case SIOC_WANPIPE_CLEAR_CALL: case SIOC_WANPIPE_RESET_CALL: if ((err=set_ioctl_cmd(sk,(void*)arg)) < 0) return err; err=wanpipe_exec_cmd(sk,cmd,0); get_ioctl_cmd(sk,(void*)arg); return err; case SIOC_WANPIPE_DEBUG: return wanpipe_debug(sk,(void*)arg); case SIOC_WANPIPE_SET_NONBLOCK: if (sk->state != WANSOCK_DISCONNECTED) return -EINVAL; sock->file->f_flags |= O_NONBLOCK; return 0; case SIOCGIFFLAGS:#ifndef CONFIG_INET case SIOCSIFFLAGS:#endif case SIOCGIFCONF: case SIOCGIFMETRIC: case SIOCSIFMETRIC: case SIOCGIFMEM: case SIOCSIFMEM: case SIOCGIFMTU: case SIOCSIFMTU: case SIOCSIFLINK: case SIOCGIFHWADDR: case SIOCSIFHWADDR: case SIOCSIFMAP: case SIOCGIFMAP: case SIOCSIFSLAVE: case SIOCGIFSLAVE: case SIOCGIFINDEX: case SIOCGIFNAME: case SIOCGIFCOUNT: case SIOCSIFHWBROADCAST: return(dev_ioctl(cmd,(void *) arg));#ifdef CONFIG_INET case SIOCADDRT: case SIOCDELRT: case SIOCDARP: case SIOCGARP: case SIOCSARP: case SIOCDRARP: case SIOCGRARP: case SIOCSRARP: case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCSIFFLAGS: case SIOCADDDLCI: case SIOCDELDLCI: return inet_dgram_ops.ioctl(sock, cmd, arg);#endif default: if ((cmd >= SIOCDEVPRIVATE) && (cmd <= (SIOCDEVPRIVATE + 15))) return(dev_ioctl(cmd,(void *) arg));#ifdef CONFIG_NET_RADIO if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) return(dev_ioctl(cmd,(void *) arg));#endif return -EOPNOTSUPP; } /*NOTREACHED*/}/*============================================================ * wanpipe_debug * * This function will pass up information about all * active sockets. * * FIXME: More thought should go into this function. * *===========================================================*/static int wanpipe_debug (struct sock *origsk, void *arg){ struct sock *sk=NULL; netdevice_t *dev=NULL; wanpipe_common_t *chan=NULL; int cnt=0, err=0; wan_debug_t *dbg_data = (wan_debug_t *)arg; for (sk = wanpipe_sklist; sk; sk = sk->next){ if (sk == origsk){ continue; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -