📄 af_wanpipe.c
字号:
mbox_ptr = (mbox_cmd_t*)wp_sk(sk)->mbox; memset(mbox_ptr, 0, sizeof(mbox_cmd_t)); if (usr_data == NULL){ return 0; } if ((err=get_user(mbox_ptr->cmd.qdm, &usr_data->hdr.qdm))) return err; if ((err=get_user(mbox_ptr->cmd.cause, &usr_data->hdr.cause))) return err; if ((err=get_user(mbox_ptr->cmd.diagn, &usr_data->hdr.diagn))) return err; if ((err=get_user(mbox_ptr->cmd.length, &usr_data->hdr.length))) return err; if ((err=get_user(mbox_ptr->cmd.result, &usr_data->hdr.result))) return err; if (mbox_ptr->cmd.length > 0){ if (mbox_ptr->cmd.length > X25_MAX_DATA) return -EINVAL; if (copy_from_user(mbox_ptr->data, usr_data->data, mbox_ptr->cmd.length)){ printk(KERN_INFO "Copy failed\n"); return -EFAULT; } } return 0;}/*====================================================================== * wanpipe_poll * * Datagram poll: Again totally generic. This also handles * sequenced packet sockets providing the socket receive queue * is only ever holding data ready to receive. * * Note: when you _don't_ use this routine for this protocol, * and you use a different write policy from sock_writeable() * then please supply your own write_space callback. *=====================================================================*/unsigned int wanpipe_poll(struct file * file, struct socket *sock, poll_table *wait){ struct sock *sk = sock->sk; unsigned int mask; ++wp_sk(sk)->poll_cnt; poll_wait(file, sk->sk_sleep, wait); mask = 0; /* exceptional events? */ if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) { mask |= POLLPRI; return mask; } if (sk->sk_shutdown & RCV_SHUTDOWN) mask |= POLLHUP; /* readable? */ if (!skb_queue_empty(&sk->sk_receive_queue)) { mask |= POLLIN | POLLRDNORM; } /* connection hasn't started yet */ if (sk->sk_state == WANSOCK_CONNECTING) { return mask; } if (sk->sk_state == WANSOCK_DISCONNECTED) { mask = POLLPRI; return mask; } /* This check blocks the user process if there is * a packet already queued in the socket write queue. * This option is only for X25API protocol, for other * protocol like chdlc enable streaming mode, * where multiple packets can be pending in the socket * transmit queue */ if (wp_sk(sk)->num == htons(X25_PROT)) { if (atomic_read(&wp_sk(sk)->packet_sent)) return mask; } /* writable? */ if (sock_writeable(sk)){ mask |= POLLOUT | POLLWRNORM | POLLWRBAND; }else{ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); } return mask;}/*====================================================================== * wanpipe_listen * * X25API Specific function. Set a socket into LISTENING MODE. *=====================================================================*/static int wanpipe_listen(struct socket *sock, int backlog){ struct sock *sk = sock->sk; /* This is x25 specific area if protocol doesn't * match, return error */ if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; if (sk->sk_state == WANSOCK_BIND_LISTEN) { sk->sk_max_ack_backlog = backlog; sk->sk_state = WANSOCK_LISTEN; return 0; }else{ printk(KERN_INFO "wansock: Listening sock was not binded\n"); } return -EINVAL;}/*====================================================================== * wanpipe_link_card * * Connects the listening socket to the driver *=====================================================================*/static int wanpipe_link_card (struct sock *sk){ sdla_t *card = (sdla_t*)wp_sk(sk)->card; if (!card) return -ENOMEM; if ((card->sk != NULL) || (card->func != NULL)){ printk(KERN_INFO "wansock: Listening queue is already established\n"); return -EINVAL; } card->sk=sk; card->func=wanpipe_listen_rcv; sk->sk_zapped = 1; return 0;}/*====================================================================== * wanpipe_listen * * X25API Specific function. Disconnect listening socket from * the driver. *=====================================================================*/static void wanpipe_unlink_card (struct sock *sk){ sdla_t *card = (sdla_t*)wp_sk(sk)->card; if (card){ card->sk=NULL; card->func=NULL; }}/*====================================================================== * wanpipe_exec_cmd * * Ioctl function calls this function to execute user command. * Connect() sytem call also calls this function to execute * place call. This function blocks until command is executed. *=====================================================================*/static int wanpipe_exec_cmd(struct sock *sk, int cmd, unsigned int flags){ int err = -EINVAL; wanpipe_opt *wp = wp_sk(sk); mbox_cmd_t *mbox_ptr = (mbox_cmd_t*)wp->mbox; if (!mbox_ptr){ printk(KERN_INFO "NO MBOX PTR !!!!!\n"); return -EINVAL; } /* This is x25 specific area if protocol doesn't * match, return error */ if (wp->num != htons(X25_PROT)) return -EINVAL; switch (cmd){ case SIOC_WANPIPE_ACCEPT_CALL: if (sk->sk_state != WANSOCK_CONNECTING) { err = -EHOSTDOWN; break; } err = execute_command(sk,X25_ACCEPT_CALL,0); if (err < 0) break; /* Update. Mar6 2000. * Do not set the sock lcn number here, since * it is done in wanpipe_listen_rcv(). */ if (sk->sk_state == WANSOCK_CONNECTED) { wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; DBG_PRINTK(KERN_INFO "\nwansock: Accept OK %i\n", wp->lcn); err = 0; }else{ DBG_PRINTK (KERN_INFO "\nwansock: Accept Failed %i\n", wp->lcn); wp->lcn = 0; err = -ECONNREFUSED; } break; case SIOC_WANPIPE_CLEAR_CALL: if (sk->sk_state == WANSOCK_DISCONNECTED) { err = -EINVAL; break; } /* Check if data buffers are pending for transmission, * if so, check whether user wants to wait until data * is transmitted, or clear a call and drop packets */ if (atomic_read(&sk->sk_wmem_alloc) || check_driver_busy(sk)) { mbox_cmd_t *mbox = wp->mbox; if (mbox->cmd.qdm & 0x80){ mbox->cmd.result = 0x35; err = -EAGAIN; break; } } sk->sk_state = WANSOCK_DISCONNECTING; err = execute_command(sk,X25_CLEAR_CALL,0); if (err < 0) break; err = -ECONNREFUSED; if (sk->sk_state == WANSOCK_DISCONNECTED) { DBG_PRINTK(KERN_INFO "\nwansock: CLEAR OK %i\n", wp->lcn); wp->lcn = 0; err = 0; } break; case SIOC_WANPIPE_RESET_CALL: if (sk->sk_state != WANSOCK_CONNECTED) { err = -EINVAL; break; } /* Check if data buffers are pending for transmission, * if so, check whether user wants to wait until data * is transmitted, or reset a call and drop packets */ if (atomic_read(&sk->sk_wmem_alloc) || check_driver_busy(sk)) { mbox_cmd_t *mbox = wp->mbox; if (mbox->cmd.qdm & 0x80){ mbox->cmd.result = 0x35; err = -EAGAIN; break; } } err = execute_command(sk, X25_RESET,0); if (err < 0) break; err = mbox_ptr->cmd.result; break; case X25_PLACE_CALL: err=execute_command(sk,X25_PLACE_CALL,flags); if (err < 0) break; if (sk->sk_state == WANSOCK_CONNECTED) { wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; DBG_PRINTK(KERN_INFO "\nwansock: PLACE CALL OK %i\n", wp->lcn); err = 0; } else if (sk->sk_state == WANSOCK_CONNECTING && (flags & O_NONBLOCK)) { wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; DBG_PRINTK(KERN_INFO "\nwansock: Place Call OK: Waiting %i\n", wp->lcn); err = 0; }else{ DBG_PRINTK(KERN_INFO "\nwansock: Place call Failed\n"); err = -ECONNREFUSED; } break; default: return -EINVAL; } return err;}static int check_driver_busy (struct sock *sk){ struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); wanpipe_common_t *chan; if (!dev) return 0; dev_put(dev); if ((chan=dev->priv) == NULL) return 0; return atomic_read(&chan->driver_busy);}/*====================================================================== * wanpipe_accept * * ACCEPT() System call. X25API Specific function. * For each incoming call, create a new socket and * return it to the user. *=====================================================================*/static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags){ struct sock *sk; struct sock *newsk; struct sk_buff *skb; DECLARE_WAITQUEUE(wait, current); int err=0; if (newsock->sk != NULL){ wanpipe_kill_sock_accept(newsock->sk); newsock->sk=NULL; } if ((sk = sock->sk) == NULL) return -EINVAL; if (sk->sk_type != SOCK_RAW) return -EOPNOTSUPP; if (sk->sk_state != WANSOCK_LISTEN) return -EINVAL; if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; add_wait_queue(sk->sk_sleep,&wait); current->state = TASK_INTERRUPTIBLE; for (;;){ skb = skb_dequeue(&sk->sk_receive_queue); if (skb){ err=0; break; } if (signal_pending(current)) { err = -ERESTARTSYS; break; } schedule(); } current->state = TASK_RUNNING; remove_wait_queue(sk->sk_sleep,&wait); if (err != 0) return err; newsk = get_newsk_from_skb(skb); if (!newsk){ return -EINVAL; } set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); sk_add_node(newsk, &wanpipe_sklist); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); newsk->sk_socket = newsock; newsk->sk_sleep = &newsock->wait; /* Now attach up the new socket */ sk->sk_ack_backlog--; newsock->sk = newsk; kfree_skb(skb); DBG_PRINTK(KERN_INFO "\nwansock: ACCEPT Got LCN %i\n", wp_sk(newsk)->lcn); return 0;}/*====================================================================== * get_newsk_from_skb * * Accept() uses this function to get the address of the new * socket structure. *=====================================================================*/struct sock * get_newsk_from_skb (struct sk_buff *skb){ struct net_device *dev = skb->dev; wanpipe_common_t *chan; if (!dev){ return NULL; } if ((chan = dev->priv) == NULL){ return NULL; } if (!chan->sk){ return NULL; } return (struct sock *)chan->sk;}/*====================================================================== * wanpipe_connect * * CONNECT() System Call. X25API specific function * Check the state of the sock, and execute PLACE_CALL command. * Connect can ether block or return without waiting for connection, * if specified by user. *=====================================================================*/static int wanpipe_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags){ struct sock *sk = sock->sk; struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr; struct net_device *dev; int err; if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; if (sk->sk_state == WANSOCK_CONNECTED) return -EISCONN; /* No reconnect on a seqpacket socket */ if (sk->sk_state != WAN_DISCONNECTED) { printk(KERN_INFO "wansock: Trying to connect on channel NON DISCONNECT\n"); return -ECONNREFUSED; } sk->sk_state = WANSOCK_DISCONNECTED; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(struct wan_sockaddr_ll)) return -EINVAL; if (addr->sll_family != AF_WANPIPE) return -EINVAL; if ((dev = dev_get_by_index(sk->sk_bound_dev_if)) == NULL) return -ENETUNREACH; dev_put(dev); if (!sk->sk_zapped) /* Must bind first - autobinding does not work */ return -EINVAL; sock->state = SS_CONNECTING; sk->sk_state = WANSOCK_CONNECTING; if (!wp_sk(sk)->mbox) { if (wp_sk (sk)->svc) return -EINVAL; else { int err; if ((err=set_ioctl_cmd(sk,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -