📄 af_decnet.c
字号:
static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table *wait){ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); int mask = datagram_poll(file, sock, wait); if (skb_queue_len(&scp->other_receive_queue)) mask |= POLLRDBAND; return mask;}static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); int err = -EOPNOTSUPP; unsigned long amount = 0; struct sk_buff *skb; int val; switch(cmd) { case SIOCGIFADDR: case SIOCSIFADDR: return dn_dev_ioctl(cmd, (void *)arg); case SIOCATMARK: lock_sock(sk); val = (skb_queue_len(&scp->other_receive_queue) != 0); if (scp->state != DN_RUN) val = -ENOTCONN; release_sock(sk); return val;#ifdef CONFIG_DECNET_ROUTER case SIOCADDRT: case SIOCDELRT: return dn_fib_ioctl(sock, cmd, arg);#endif /* CONFIG_DECNET_ROUTER */ case OSIOCSNETADDR: if (!capable(CAP_NET_ADMIN)) { err = -EPERM; break; } dn_dev_devices_off(); decnet_address = (unsigned short)arg; dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); dn_dev_devices_on(); err = 0; break; case OSIOCGNETADDR: err = put_user(decnet_address, (unsigned short *)arg); break; case SIOCGIFCONF: case SIOCGIFFLAGS: case SIOCGIFBRDADDR: return dev_ioctl(cmd,(void *)arg); case TIOCOUTQ: amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; err = put_user(amount, (int *)arg); break; case TIOCINQ: lock_sock(sk); if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) { amount = skb->len; } else { struct sk_buff *skb = sk->receive_queue.next; for(;;) { if (skb == (struct sk_buff *)&sk->receive_queue) break; amount += skb->len; skb = skb->next; } } release_sock(sk); err = put_user(amount, (int *)arg); break; } return err;}static int dn_listen(struct socket *sock, int backlog){ struct sock *sk = sock->sk; int err = -EINVAL; lock_sock(sk); if (sk->zapped) goto out; if ((DN_SK(sk)->state != DN_O) || (sk->state == TCP_LISTEN)) goto out; sk->max_ack_backlog = backlog; sk->ack_backlog = 0; sk->state = TCP_LISTEN; err = 0; dn_rehash_sock(sk);out: release_sock(sk); return err;}static int dn_shutdown(struct socket *sock, int how){ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); int err = -ENOTCONN; lock_sock(sk); if (sock->state == SS_UNCONNECTED) goto out; err = 0; if (sock->state == SS_DISCONNECTING) goto out; err = -EINVAL; if (scp->state == DN_O) goto out; if (how != SHUTDOWN_MASK) goto out; sk->shutdown = how; dn_destroy_sock(sk); err = 0;out: release_sock(sk); return err;}static int dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen){ struct sock *sk = sock->sk; int err; lock_sock(sk); err = __dn_setsockopt(sock, level, optname, optval, optlen, 0); release_sock(sk); return err;}static int __dn_setsockopt(struct socket *sock, int level,int optname, char *optval, int optlen, int flags) { struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); union { struct optdata_dn opt; struct accessdata_dn acc; int mode; unsigned long win; int val; unsigned char services; unsigned char info; } u; int err; if (optlen && !optval) return -EINVAL; if (optlen > sizeof(u)) return -EINVAL; if (copy_from_user(&u, optval, optlen)) return -EFAULT; switch(optname) { case DSO_CONDATA: if (sock->state == SS_CONNECTED) return -EISCONN; if ((scp->state != DN_O) && (scp->state != DN_CR)) return -EINVAL; if (optlen != sizeof(struct optdata_dn)) return -EINVAL; if (u.opt.opt_optl > 16) return -EINVAL; memcpy(&scp->conndata_out, &u.opt, optlen); break; case DSO_DISDATA: if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED) return -ENOTCONN; if (optlen != sizeof(struct optdata_dn)) return -EINVAL; if (u.opt.opt_optl > 16) return -EINVAL; memcpy(&scp->discdata_out, &u.opt, optlen); break; case DSO_CONACCESS: if (sock->state == SS_CONNECTED) return -EISCONN; if (scp->state != DN_O) return -EINVAL; if (optlen != sizeof(struct accessdata_dn)) return -EINVAL; if ((u.acc.acc_accl > DN_MAXACCL) || (u.acc.acc_passl > DN_MAXACCL) || (u.acc.acc_userl > DN_MAXACCL)) return -EINVAL; memcpy(&scp->accessdata, &u.acc, optlen); break; case DSO_ACCEPTMODE: if (sock->state == SS_CONNECTED) return -EISCONN; if (scp->state != DN_O) return -EINVAL; if (optlen != sizeof(int)) return -EINVAL; if ((u.mode != ACC_IMMED) && (u.mode != ACC_DEFER)) return -EINVAL; scp->accept_mode = (unsigned char)u.mode; break; case DSO_CONACCEPT: if (scp->state != DN_CR) return -EINVAL; scp->state = DN_CC; dn_send_conn_conf(sk, sk->allocation); err = dn_wait_accept(sock, sock->file->f_flags); return err; case DSO_CONREJECT: if (scp->state != DN_CR) return -EINVAL; scp->state = DN_DR; sk->shutdown = SHUTDOWN_MASK; dn_nsp_send_disc(sk, 0x38, 0, sk->allocation); break; default:#ifdef CONFIG_NETFILTER return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);#endif case DSO_LINKINFO: case DSO_STREAM: case DSO_SEQPACKET: return -ENOPROTOOPT; case DSO_MAXWINDOW: if (optlen != sizeof(unsigned long)) return -EINVAL; if (u.win > NSP_MAX_WINDOW) u.win = NSP_MAX_WINDOW; if (u.win == 0) return -EINVAL; scp->max_window = u.win; if (scp->snd_window > u.win) scp->snd_window = u.win; break; case DSO_NODELAY: if (optlen != sizeof(int)) return -EINVAL; if (scp->nonagle == 2) return -EINVAL; scp->nonagle = (u.val == 0) ? 0 : 1; /* if (scp->nonagle == 1) { Push pending frames } */ break; case DSO_CORK: if (optlen != sizeof(int)) return -EINVAL; if (scp->nonagle == 1) return -EINVAL; scp->nonagle = (u.val == 0) ? 0 : 2; /* if (scp->nonagle == 0) { Push pending frames } */ break; case DSO_SERVICES: if (optlen != sizeof(unsigned char)) return -EINVAL; if ((u.services & ~NSP_FC_MASK) != 0x01) return -EINVAL; if ((u.services & NSP_FC_MASK) == NSP_FC_MASK) return -EINVAL; scp->services_loc = u.services; break; case DSO_INFO: if (optlen != sizeof(unsigned char)) return -EINVAL; if (u.info & 0xfc) return -EINVAL; scp->info_loc = u.info; break; } return 0;}static int dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen){ struct sock *sk = sock->sk; int err; lock_sock(sk); err = __dn_getsockopt(sock, level, optname, optval, optlen, 0); release_sock(sk); return err;}static int __dn_getsockopt(struct socket *sock, int level,int optname, char *optval,int *optlen, int flags){ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); struct linkinfo_dn link; unsigned int r_len; void *r_data = NULL; unsigned int val; if(get_user(r_len , optlen)) return -EFAULT; switch(optname) { case DSO_CONDATA: if (r_len > sizeof(struct optdata_dn)) r_len = sizeof(struct optdata_dn); r_data = &scp->conndata_in; break; case DSO_DISDATA: if (r_len > sizeof(struct optdata_dn)) r_len = sizeof(struct optdata_dn); r_data = &scp->discdata_in; break; case DSO_CONACCESS: if (r_len > sizeof(struct accessdata_dn)) r_len = sizeof(struct accessdata_dn); r_data = &scp->accessdata; break; case DSO_ACCEPTMODE: if (r_len > sizeof(unsigned char)) r_len = sizeof(unsigned char); r_data = &scp->accept_mode; break; case DSO_LINKINFO: if (r_len > sizeof(struct linkinfo_dn)) r_len = sizeof(struct linkinfo_dn); switch(sock->state) { case SS_CONNECTING: link.idn_linkstate = LL_CONNECTING; break; case SS_DISCONNECTING: link.idn_linkstate = LL_DISCONNECTING; break; case SS_CONNECTED: link.idn_linkstate = LL_RUNNING; break; default: link.idn_linkstate = LL_INACTIVE; } link.idn_segsize = scp->segsize_rem; r_data = &link; break; default:#ifdef CONFIG_NETFILTER { int val, len; if(get_user(len, optlen)) return -EFAULT; val = nf_getsockopt(sk, PF_DECnet, optname, optval, &len); if (val >= 0) val = put_user(len, optlen); return val; }#endif case DSO_STREAM: case DSO_SEQPACKET: case DSO_CONACCEPT: case DSO_CONREJECT: return -ENOPROTOOPT; case DSO_MAXWINDOW: if (r_len > sizeof(unsigned long)) r_len = sizeof(unsigned long); r_data = &scp->max_window; break; case DSO_NODELAY: if (r_len > sizeof(int)) r_len = sizeof(int); val = (scp->nonagle == 1); r_data = &val; break; case DSO_CORK: if (r_len > sizeof(int)) r_len = sizeof(int); val = (scp->nonagle == 2); r_data = &val; break; case DSO_SERVICES: if (r_len > sizeof(unsigned char)) r_len = sizeof(unsigned char); r_data = &scp->services_rem; break; case DSO_INFO: if (r_len > sizeof(unsigned char)) r_len = sizeof(unsigned char); r_data = &scp->info_rem; break; } if (r_data) { if (copy_to_user(optval, r_data, r_len)) return -EFAULT; if (put_user(r_len, optlen)) return -EFAULT; } return 0;}/* * Used by send/recvmsg to wait until the socket is connected * before passing data. */static int dn_wait_run(struct sock *sk, int flags){ struct dn_scp *scp = DN_SK(sk); int err = 0; switch(scp->state) { case DN_RUN: return 0; case DN_CR: scp->state = DN_CC; dn_send_conn_conf(sk, sk->allocation); return dn_wait_accept(sk->socket, (flags & MSG_DONTWAIT) ? O_NONBLOCK : 0); case DN_CI: case DN_CC: break; default: return -ENOTCONN; } if (flags & MSG_DONTWAIT) return -EWOULDBLOCK; do { if ((err = sock_error(sk)) != 0) break; if (signal_pending(current)) { err = -ERESTARTSYS; break; } SOCK_SLEEP_PRE(sk) if (scp->state != DN_RUN) schedule(); SOCK_SLEEP_POST(sk) } while(scp->state != DN_RUN); return 0;}static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int target){ struct sk_buff *skb = q->next; int len = 0; if (flags & MSG_OOB) return skb_queue_len(q) ? 1 : 0; while(skb != (struct sk_buff *)q) { struct dn_skb_cb *cb = DN_SKB_CB(skb); len += skb->len; if (cb->nsp_flags & 0x40) { /* SOCK_SEQPACKET reads to EOM */ if (sk->type == SOCK_SEQPACKET) return 1; /* so does SOCK_STREAM unless WAITALL is specified */ if (!(flags & MSG_WAITALL)) return 1; } /* minimum data length for read exceeded */ if (len >= target) return 1; skb = skb->next; } return 0;}static int dn_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); struct sk_buff_head *queue = &sk->receive_queue; int target = size > 1 ? 1 : 0; int copied = 0; int rv = 0; struct sk_buff *skb, *nskb; struct dn_skb_cb *cb = NULL; unsigned char eor = 0; lock_sock(sk); if (sk->zapped) { rv = -EADDRNOTAVAIL; goto out; } if ((rv = dn_wait_run(sk, flags)) != 0) goto out; if (sk->shutdown & RCV_SHUTDOWN) { send_sig(SIGPIPE, current, 0); rv = -EPIPE; goto out; } if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT)) { rv = -EOPNOTSUPP; goto out; } if (flags & MSG_OOB)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -