📄 af_wanpipe.c
字号:
sk->sk_reuse = 1; sock->ops = &wanpipe_ops; sock_init_data(sock,sk); sk->sk_zapped = 0; sk->sk_family = PF_WANPIPE; wp_sk(sk)->num = protocol; sk->sk_state = WANSOCK_DISCONNECTED; sk->sk_ack_backlog = 0; sk->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_add_node(sk, &wanpipe_sklist); 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 kiocb *iocb, struct socket *sock, struct msghdr *msg, int len, int flags){ 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->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; sock_recv_timestamp(msg, sk, skb); 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){ struct net_device *dev = NULL; wanpipe_common_t *chan=NULL; dev = dev_get_by_index(sk->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->sk_rmem_alloc) < ((unsigned)sk->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){ struct net_device *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->sk_bound_dev_if; sll->sll_protocol = wp_sk(sk)->num; dev = dev_get_by_index(sk->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; hlist_node *node; struct net_device *dev = (struct net_device *)data; sk_for_each(sk, node, &wanpipe_sklist) { struct wanpipe_opt *po = wp_sk(sk); if (!po) continue; if (dev == NULL) continue; switch (msg) { case NETDEV_DOWN: case NETDEV_UNREGISTER: if (dev->ifindex == sk->sk_bound_dev_if) { printk(KERN_INFO "wansock: Device down %s\n",dev->name); if (sk->sk_zapped) { wanpipe_unlink_driver(sk); sk->sk_err = ENETDOWN; sk->sk_error_report(sk); } if (msg == NETDEV_UNREGISTER) { printk(KERN_INFO "wansock: Unregistering Device: %s\n", dev->name); wanpipe_unlink_driver(sk); sk->sk_bound_dev_if = 0; } } break; case NETDEV_UP: if (dev->ifindex == sk->sk_bound_dev_if && po->num && !sk->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; switch(cmd) { case SIOCGSTAMP: return sock_get_timestamp(sk, (struct timeval __user *)arg); case SIOC_WANPIPE_CHECK_TX: return atomic_read(&sk->sk_wmem_alloc); case SIOC_WANPIPE_SOCK_STATE: if (sk->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->sk_state != WANSOCK_DISCONNECTED) return -EINVAL; sock->file->f_flags |= O_NONBLOCK; return 0; #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: return inet_dgram_ops.ioctl(sock, cmd, arg);#endif default: return dev_ioctl(cmd,(void __user *) arg); } /*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; struct hlist_node *node; struct net_device *dev = NULL; wanpipe_common_t *chan=NULL; int cnt=0, err=0; wan_debug_t *dbg_data = (wan_debug_t *)arg; sk_for_each(sk, node, &wanpipe_sklist) { wanpipe_opt *wp = wp_sk(sk); if (sk == origsk){ continue; } if ((err=put_user(1, &dbg_data->debug[cnt].free))) return err; if ((err = put_user(sk->sk_state, &dbg_data->debug[cnt].state_sk))) return err; if ((err = put_user(sk->sk_rcvbuf, &dbg_data->debug[cnt].rcvbuf))) return err; if ((err = put_user(atomic_read(&sk->sk_rmem_alloc), &dbg_data->debug[cnt].rmem))) return err; if ((err = put_user(atomic_read(&sk->sk_wmem_alloc), &dbg_data->debug[cnt].wmem))) return err; if ((err = put_user(sk->sk_sndbuf, &dbg_data->debug[cnt].sndbuf))) return err; if ((err=put_user(sk_count, &dbg_data->debug[cnt].sk_count))) return err; if ((err=put_user(wp->poll_cnt, &dbg_data->debug[cnt].poll_cnt))) return err; if ((err = put_user(sk->sk_bound_dev_if, &dbg_data->debug[cnt].bound))) return err; if (sk->sk_bound_dev_if) { dev = dev_get_by_index(sk->sk_bound_dev_if); if (!dev) continue; chan=dev->priv; dev_put(dev); if ((err=put_user(chan->state, &dbg_data->debug[cnt].d_state))) return err; if ((err=put_user(chan->svc, &dbg_data->debug[cnt].svc))) return err; if ((err=put_user(atomic_read(&chan->command), &dbg_data->debug[cnt].command))) return err; if (wp){ sdla_t *card = (sdla_t*)wp->card; if (card){ if ((err=put_user(atomic_read(&card->u.x.command_busy), &dbg_data->debug[cnt].cmd_busy))) return err; } if ((err=put_user(wp->lcn, &dbg_data->debug[cnt].lcn))) return err; if (wp->mbox) { if ((err=put_user(1, &dbg_data->debug[cnt].mbox))) return err; } } if ((err=put_user(atomic_read(&chan->receive_block), &dbg_data->debug[cnt].rblock))) return err; if (copy_to_user(dbg_data->debug[cnt].name, dev->name, strlen(dev->name))) return -EFAULT; } if (++cnt == MAX_NUM_DEBUG) break; } return 0;}/*============================================================ * get_ioctl_cmd * * Pass up the contents of socket MBOX to the user. *===========================================================*/static int get_ioctl_cmd (struct sock *sk, void *arg){ x25api_t *usr_data = (x25api_t *)arg; mbox_cmd_t *mbox_ptr; int err; if (usr_data == NULL) return -EINVAL; if (!wp_sk(sk)->mbox) { return -EINVAL; } mbox_ptr = (mbox_cmd_t *)wp_sk(sk)->mbox; if ((err=put_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) return err; if ((err=put_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) return err; if ((err=put_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) return err; if ((err=put_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) return err; if ((err=put_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) return err; if ((err=put_user(mbox_ptr->cmd.lcn, &usr_data->hdr.lcn))) return err; if (mbox_ptr->cmd.length > 0){ if (mbox_ptr->cmd.length > X25_MAX_DATA) return -EINVAL; if (copy_to_user(usr_data->data, mbox_ptr->data, mbox_ptr->cmd.length)){ printk(KERN_INFO "wansock: Copy failed !!!\n"); return -EFAULT; } } return 0;} /*============================================================ * set_ioctl_cmd * * Before command can be execute, socket MBOX must * be created, and initialized with user data. *===========================================================*/static int set_ioctl_cmd (struct sock *sk, void *arg){ x25api_t *usr_data = (x25api_t *)arg; mbox_cmd_t *mbox_ptr; int err; if (!wp_sk(sk)->mbox) { void *mbox_ptr; struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); if (!dev) return -ENODEV; dev_put(dev); if ((mbox_ptr = kmalloc(sizeof(mbox_cmd_t), GFP_ATOMIC)) == NULL) return -ENOMEM; memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); wp_sk(sk)->mbox = mbox_ptr; wanpipe_link_driver(dev,sk); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -