📄 af_decnet.c
字号:
static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; int err = -EOPNOTSUPP; unsigned long amount = 0; struct sk_buff *skb;#if 0 struct dn_naddr dnaddr;#endif switch(cmd) { case SIOCGIFADDR: case SIOCSIFADDR: return dn_dev_ioctl(cmd, (void *)arg);#ifdef CONFIG_DECNET_ROUTER case SIOCADDRT: case SIOCDELRT: return dn_fib_ioctl(sock, cmd, arg);#endif /* CONFIG_DECNET_ROUTER */#if 0 case SIOCSIFADDR: if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((err = copy_from_user(devname, ioarg->devname, 5)) != 0) break; if ((err = copy_from_user(addr, ioarg->exec_addr, 6)) != 0) break; if ((dev = dev_get(devname)) == NULL) { err = -ENODEV; break; } if (dev->dn_ptr == NULL) { err = -ENODEV; break; } dn_dev_devices_off(); decnet_default_device = dev; memcpy(decnet_ether_address, addr, ETH_ALEN); decnet_address = dn_htons(dn_eth2dn(decnet_ether_address)); dn_dev_devices_on(); break; case SIOCGIFADDR: if (decnet_default_device) strcpy(devname, decnet_default_device->name); else memset(devname, 0, 6); if ((err = copy_to_user(ioarg->devname, devname, 5)) != 0) break; if ((err = copy_to_user(ioarg->exec_addr, decnet_ether_address, 6)) != 0) break; break;#endif#if 0 case SIOCSNETADDR: if (!capable(CAP_NET_ADMIN)) { err = -EPERM; break; } if ((err = copy_from_user(&dnaddr, (void *)arg, sizeof(struct dn_naddr))) != 0) break; if (dnaddr.a_len != ETH_ALEN) { err = -EINVAL; break; } dn_dev_devices_off(); memcpy(decnet_ether_address, dnaddr.a_addr, ETH_ALEN); decnet_address = dn_htons(dn_eth2dn(decnet_ether_address)); dn_dev_devices_on(); break; case SIOCGNETADDR: dnaddr.a_len = ETH_ALEN; memcpy(dnaddr.a_addr, decnet_ether_address, ETH_ALEN); if ((err = copy_to_user((void *)arg, &dnaddr, sizeof(struct dn_naddr))) != 0) break; break;#endif 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 ((sk->protinfo.dn.state != DN_O) || (sk->state == TCP_LISTEN)) goto out; sk->max_ack_backlog = backlog; sk->ack_backlog = 0; sk->state = TCP_LISTEN; err = 0;out: release_sock(sk); return err;}static int dn_shutdown(struct socket *sock, int how){ struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; 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 = &sk->protinfo.dn; struct optdata_dn opt; struct accessdata_dn acc; int err; if (optlen && !optval) return -EINVAL; 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 (copy_from_user(&opt, optval, optlen)) return -EFAULT; if (opt.opt_optl > 16) return -EINVAL; memcpy(&scp->conndata_out, &opt, sizeof(struct optdata_dn)); break; case DSO_DISDATA: if (sock->state != SS_CONNECTED && sk->protinfo.dn.accept_mode == ACC_IMMED) return -ENOTCONN; if (optlen != sizeof(struct optdata_dn)) return -EINVAL; if (copy_from_user(&opt, optval, sizeof(struct optdata_dn))) return -EFAULT; if (opt.opt_optl > 16) return -EINVAL; memcpy(&scp->discdata_out, &opt, sizeof(struct optdata_dn)); 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 (copy_from_user(&acc, optval, sizeof(struct accessdata_dn))) return -EFAULT; if ((acc.acc_accl > DN_MAXACCL) || (acc.acc_passl > DN_MAXACCL) || (acc.acc_userl > DN_MAXACCL)) return -EINVAL; memcpy(&scp->accessdata, &acc, sizeof(struct accessdata_dn)); break; case DSO_ACCEPTMODE: if (sock->state == SS_CONNECTED) return -EISCONN; if (scp->state != DN_O) return -EINVAL; if (optlen != sizeof(int)) return -EINVAL; { int mode; if (get_user(mode, optval)) return -EFAULT; if ((mode != ACC_IMMED) && (mode != ACC_DEFER)) return -EINVAL; scp->accept_mode = (unsigned char)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; } 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 = &sk->protinfo.dn; struct linkinfo_dn link; int mode = scp->accept_mode; switch(optname) { case DSO_CONDATA: if (*optlen != sizeof(struct optdata_dn)) return -EINVAL; if (copy_to_user(optval, &scp->conndata_in, sizeof(struct optdata_dn))) return -EFAULT; break; case DSO_DISDATA: if (*optlen != sizeof(struct optdata_dn)) return -EINVAL; if (copy_to_user(optval, &scp->discdata_in, sizeof(struct optdata_dn))) return -EFAULT; break; case DSO_CONACCESS: if (*optlen != sizeof(struct accessdata_dn)) return -EINVAL; if (copy_to_user(optval, &scp->accessdata, sizeof(struct accessdata_dn))) return -EFAULT; break; case DSO_ACCEPTMODE: if (put_user(mode, optval)) return -EFAULT; break; case DSO_LINKINFO: if (*optlen != sizeof(struct linkinfo_dn)) return -EINVAL; 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->mss; if (copy_to_user(optval, &link, sizeof(struct linkinfo_dn))) return -EFAULT; break; default:#ifdef CONFIG_NETFILTER { int val, len = *optlen; 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; } 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 = &sk->protinfo.dn; 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 = (struct dn_skb_cb *)skb->cb; 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 = &sk->protinfo.dn; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -