📄 af_decnet.c
字号:
switch(scp->state) { case DN_DN: dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, sk->allocation); scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); break; case DN_CR: scp->state = DN_DR; goto disc_reject; case DN_RUN: scp->state = DN_DI; case DN_DI: case DN_DR:disc_reject: dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->allocation); case DN_NC: case DN_NR: case DN_RJ: case DN_DIC: case DN_CN: case DN_DRC: case DN_CI: case DN_CD: scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); break; default: printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n"); case DN_O: dn_stop_fast_timer(sk); dn_stop_slow_timer(sk); dn_unhash_sock_bh(sk); sock_put(sk); break; }}char *dn_addr2asc(dn_address addr, char *buf){ unsigned short node, area; node = addr & 0x03ff; area = addr >> 10; sprintf(buf, "%hd.%hd", area, node); return buf;}static char *dn_state2asc(unsigned char state){ switch(state) { case DN_O: return "OPEN"; case DN_CR: return " CR"; case DN_DR: return " DR"; case DN_DRC: return " DRC"; case DN_CC: return " CC"; case DN_CI: return " CI"; case DN_NR: return " NR"; case DN_NC: return " NC"; case DN_CD: return " CD"; case DN_RJ: return " RJ"; case DN_RUN: return " RUN"; case DN_DI: return " DI"; case DN_DIC: return " DIC"; case DN_DN: return " DN"; case DN_CL: return " CL"; case DN_CN: return " CN"; } return "????";}static int dn_create(struct socket *sock, int protocol){ struct sock *sk; switch(sock->type) { case SOCK_SEQPACKET: if (protocol != DNPROTO_NSP) return -EPROTONOSUPPORT; break; case SOCK_STREAM: break; default: return -ESOCKTNOSUPPORT; } if ((sk = dn_alloc_sock(sock, GFP_KERNEL)) == NULL) return -ENOBUFS; sk->protocol = protocol; return 0;}static intdn_release(struct socket *sock){ struct sock *sk = sock->sk; if (sk) { sock_orphan(sk); sock_hold(sk); lock_sock(sk); dn_destroy_sock(sk); release_sock(sk); sock_put(sk); } return 0;}static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){ struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr; struct net_device *dev; int rv; if (sk->zapped == 0) return -EINVAL; if (addr_len != sizeof(struct sockaddr_dn)) return -EINVAL; if (saddr->sdn_family != AF_DECnet) return -EINVAL; if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2)) return -EINVAL; if (saddr->sdn_objnum && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL) return -EINVAL; if (saddr->sdn_flags & ~SDF_WILD) return -EINVAL; if (saddr->sdn_flags & SDF_WILD) { if (!capable(CAP_NET_BIND_SERVICE)) return -EPERM; } else { if (dn_ntohs(saddr->sdn_nodeaddrl)) { read_lock(&dev_base_lock); for(dev = dev_base; dev; dev = dev->next) { if (!dev->dn_ptr) continue; if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) break; } read_unlock(&dev_base_lock); if (dev == NULL) return -EADDRNOTAVAIL; } } memcpy(&scp->addr, saddr, addr_len); sk->zapped = 0; if ((rv = dn_hash_sock(sk)) == 0) goto out; sk->zapped = 1;out: return rv;}static int dn_auto_bind(struct socket *sock){ struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; sk->zapped = 0; scp->addr.sdn_flags = 0; scp->addr.sdn_objnum = 0; /* * This stuff is to keep compatibility with Eduardo's * patch. I hope I can dispense with it shortly... */ if ((scp->accessdata.acc_accl != 0) && (scp->accessdata.acc_accl <= 12)) { scp->addr.sdn_objnamel = dn_htons(scp->accessdata.acc_accl); memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, dn_ntohs(scp->addr.sdn_objnamel)); scp->accessdata.acc_accl = 0; memset(scp->accessdata.acc_acc, 0, 40); } scp->addr.sdn_add.a_len = dn_htons(2); *(dn_address *)scp->addr.sdn_add.a_addr = decnet_address; dn_hash_sock(sk); return 0;}static int dn_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags){ struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr; struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; int err = -EISCONN; lock_sock(sk); if (sock->state == SS_CONNECTED) goto out; if (sock->state == SS_CONNECTING) { err = 0; if (sk->state == TCP_ESTABLISHED) goto out; err = -ECONNREFUSED; if (sk->state == TCP_CLOSE) goto out; } err = -EINVAL; if (sk->protinfo.dn.state != DN_O) goto out; if (addr_len != sizeof(struct sockaddr_dn)) goto out; if (addr->sdn_family != AF_DECnet) goto out; if (addr->sdn_flags & SDF_WILD) goto out; err = -EADDRNOTAVAIL; if (sk->zapped && (err = dn_auto_bind(sock))) goto out; memcpy(&scp->peer, addr, addr_len); err = -EHOSTUNREACH; if (dn_route_output(&sk->dst_cache, dn_saddr2dn(&scp->peer), dn_saddr2dn(&scp->addr), 0) < 0) goto out; sk->state = TCP_SYN_SENT; sock->state = SS_CONNECTING; sk->protinfo.dn.state = DN_CI; dn_nsp_send_conninit(sk, NSP_CI); err = -EINPROGRESS; if ((sk->state == TCP_SYN_SENT) && (flags & O_NONBLOCK)) goto out; while(sk->state == TCP_SYN_SENT) { err = -ERESTARTSYS; if (signal_pending(current)) goto out; if ((err = sock_error(sk)) != 0) { sock->state = SS_UNCONNECTED; goto out; } SOCK_SLEEP_PRE(sk); if (sk->state == TCP_SYN_SENT) schedule(); SOCK_SLEEP_POST(sk); } if (sk->state != TCP_ESTABLISHED) { sock->state = SS_UNCONNECTED; err = sock_error(sk); goto out; } err = 0; sock->state = SS_CONNECTED;out: release_sock(sk); return err;}static int dn_access_copy(struct sk_buff *skb, struct accessdata_dn *acc){ unsigned char *ptr = skb->data; acc->acc_userl = *ptr++; memcpy(&acc->acc_user, ptr, acc->acc_userl); ptr += acc->acc_userl; acc->acc_passl = *ptr++; memcpy(&acc->acc_pass, ptr, acc->acc_passl); ptr += acc->acc_passl; acc->acc_accl = *ptr++; memcpy(&acc->acc_acc, ptr, acc->acc_accl); skb_pull(skb, acc->acc_accl + acc->acc_passl + acc->acc_userl + 3); return 0;}static int dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt){ unsigned char *ptr = skb->data; opt->opt_optl = *ptr++; opt->opt_status = 0; memcpy(opt->opt_data, ptr, opt->opt_optl); skb_pull(skb, opt->opt_optl + 1); return 0;}/* * This is here for use in the sockopt() call as well as * in accept(). Must be called with a locked socket. */static int dn_wait_accept(struct socket *sock, int flags){ struct sock *sk = sock->sk; while(sk->state == TCP_LISTEN) { if (flags & O_NONBLOCK) { return -EAGAIN; } SOCK_SLEEP_PRE(sk) if (sk->state == TCP_LISTEN) schedule(); SOCK_SLEEP_POST(sk) if (signal_pending(current)) return -ERESTARTSYS; /* But of course you don't! */ } if ((sk->protinfo.dn.state != DN_RUN) && (sk->protinfo.dn.state != DN_DRC)) { sock->state = SS_UNCONNECTED; return sock_error(sk); } sock->state = SS_CONNECTED; return 0;}static int dn_accept(struct socket *sock, struct socket *newsock, int flags){ struct sock *sk = sock->sk, *newsk; struct sk_buff *skb = NULL; struct dn_skb_cb *cb; unsigned char menuver; int err = 0; unsigned char type; lock_sock(sk); if (sk->state != TCP_LISTEN) { release_sock(sk); return -EINVAL; } if (sk->protinfo.dn.state != DN_O) { release_sock(sk); return -EINVAL; } do { if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { if (flags & O_NONBLOCK) { release_sock(sk); return -EAGAIN; } SOCK_SLEEP_PRE(sk); if (!skb_peek(&sk->receive_queue)) schedule(); SOCK_SLEEP_POST(sk); if (signal_pending(current)) { release_sock(sk); return -ERESTARTSYS; } } } while (skb == NULL); cb = (struct dn_skb_cb *)skb->cb; if ((newsk = dn_alloc_sock(newsock, sk->allocation)) == NULL) { release_sock(sk); kfree_skb(skb); return -ENOBUFS; } sk->ack_backlog--; release_sock(sk); dst_release(xchg(&newsk->dst_cache, skb->dst)); skb->dst = NULL; newsk->protinfo.dn.state = DN_CR; newsk->protinfo.dn.addrrem = cb->src_port; newsk->protinfo.dn.mss = cb->segsize; newsk->protinfo.dn.accept_mode = sk->protinfo.dn.accept_mode; if (newsk->protinfo.dn.mss < 230) newsk->protinfo.dn.mss = 230; newsk->state = TCP_LISTEN; newsk->zapped = 0; memcpy(&newsk->protinfo.dn.addr, &sk->protinfo.dn.addr, sizeof(struct sockaddr_dn)); /* * If we are listening on a wild socket, we don't want * the newly created socket on the wrong hash queue. */ newsk->protinfo.dn.addr.sdn_flags &= ~SDF_WILD; skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.addr, &type)); skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.peer, &type)); *(dn_address *)newsk->protinfo.dn.peer.sdn_add.a_addr = cb->src; *(dn_address *)newsk->protinfo.dn.addr.sdn_add.a_addr = cb->dst; menuver = *skb->data; skb_pull(skb, 1); if (menuver & DN_MENUVER_ACC) dn_access_copy(skb, &newsk->protinfo.dn.accessdata); if (menuver & DN_MENUVER_USR) dn_user_copy(skb, &newsk->protinfo.dn.conndata_in); if (menuver & DN_MENUVER_PRX) newsk->protinfo.dn.peer.sdn_flags |= SDF_PROXY; if (menuver & DN_MENUVER_UIC) newsk->protinfo.dn.peer.sdn_flags |= SDF_UICPROXY; kfree_skb(skb); memcpy(&newsk->protinfo.dn.conndata_out, &sk->protinfo.dn.conndata_out, sizeof(struct optdata_dn)); memcpy(&newsk->protinfo.dn.discdata_out, &sk->protinfo.dn.discdata_out, sizeof(struct optdata_dn)); lock_sock(newsk); dn_hash_sock(newsk); dn_send_conn_ack(newsk); if (newsk->protinfo.dn.accept_mode == ACC_IMMED) { newsk->protinfo.dn.state = DN_CC; dn_send_conn_conf(newsk, newsk->allocation); err = dn_wait_accept(newsock, flags); } release_sock(newsk); return err;}static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len,int peer){ struct sockaddr_dn *sa = (struct sockaddr_dn *)uaddr; struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; *uaddr_len = sizeof(struct sockaddr_dn); lock_sock(sk); if (peer) { if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED) return -ENOTCONN; memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn)); } else { memcpy(sa, &scp->addr, sizeof(struct sockaddr_dn)); } release_sock(sk); return 0;}static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table *wait){ struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; int mask = datagram_poll(file, sock, wait); if (skb_queue_len(&scp->other_receive_queue)) mask |= POLLRDBAND; return mask;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -