📄 af_decnet.c
字号:
static void dn_destroy_sock(struct sock *sk){ struct dn_scp *scp = DN_SK(sk); scp->nsp_rxtshift = 0; /* reset back off */ if (sk->sk_socket) { if (sk->sk_socket->state != SS_UNCONNECTED) sk->sk_socket->state = SS_DISCONNECTING; } sk->sk_state = TCP_CLOSE; switch(scp->state) { case DN_DN: dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, sk->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->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_slow_timer(sk); dn_unhash_sock_bh(sk); sock_put(sk); break; }}char *dn_addr2asc(__u16 addr, char *buf){ unsigned short node, area; node = addr & 0x03ff; area = addr >> 10; sprintf(buf, "%hd.%hd", area, node); return buf;}static int dn_create(struct net *net, struct socket *sock, int protocol){ struct sock *sk; if (net != &init_net) return -EAFNOSUPPORT; 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(net, sock, GFP_KERNEL)) == NULL) return -ENOBUFS; sk->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 = DN_SK(sk); struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr; struct net_device *dev, *ldev; int rv; 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 (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL) return -EINVAL; if (saddr->sdn_flags & ~SDF_WILD) return -EINVAL; if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD))) return -EACCES; if (!(saddr->sdn_flags & SDF_WILD)) { if (dn_ntohs(saddr->sdn_nodeaddrl)) { read_lock(&dev_base_lock); ldev = NULL; for_each_netdev(&init_net, dev) { if (!dev->dn_ptr) continue; if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) { ldev = dev; break; } } read_unlock(&dev_base_lock); if (ldev == NULL) return -EADDRNOTAVAIL; } } rv = -EINVAL; lock_sock(sk); if (sock_flag(sk, SOCK_ZAPPED)) { memcpy(&scp->addr, saddr, addr_len); sock_reset_flag(sk, SOCK_ZAPPED); rv = dn_hash_sock(sk); if (rv) sock_set_flag(sk, SOCK_ZAPPED); } release_sock(sk); return rv;}static int dn_auto_bind(struct socket *sock){ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); int rv; sock_reset_flag(sk, SOCK_ZAPPED); 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); } /* End of compatibility stuff */ scp->addr.sdn_add.a_len = dn_htons(2); rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr); if (rv == 0) { rv = dn_hash_sock(sk); if (rv) sock_set_flag(sk, SOCK_ZAPPED); } return rv;}static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation){ struct dn_scp *scp = DN_SK(sk); DEFINE_WAIT(wait); int err; if (scp->state != DN_CR) return -EINVAL; scp->state = DN_CC; scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS); dn_send_conn_conf(sk, allocation); prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); for(;;) { release_sock(sk); if (scp->state == DN_CC) *timeo = schedule_timeout(*timeo); lock_sock(sk); err = 0; if (scp->state == DN_RUN) break; err = sock_error(sk); if (err) break; err = sock_intr_errno(*timeo); if (signal_pending(current)) break; err = -EAGAIN; if (!*timeo) break; prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); if (err == 0) { sk->sk_socket->state = SS_CONNECTED; } else if (scp->state != DN_CC) { sk->sk_socket->state = SS_UNCONNECTED; } return err;}static int dn_wait_run(struct sock *sk, long *timeo){ struct dn_scp *scp = DN_SK(sk); DEFINE_WAIT(wait); int err = 0; if (scp->state == DN_RUN) goto out; if (!*timeo) return -EALREADY; prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); for(;;) { release_sock(sk); if (scp->state == DN_CI || scp->state == DN_CC) *timeo = schedule_timeout(*timeo); lock_sock(sk); err = 0; if (scp->state == DN_RUN) break; err = sock_error(sk); if (err) break; err = sock_intr_errno(*timeo); if (signal_pending(current)) break; err = -ETIMEDOUT; if (!*timeo) break; prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait);out: if (err == 0) { sk->sk_socket->state = SS_CONNECTED; } else if (scp->state != DN_CI && scp->state != DN_CC) { sk->sk_socket->state = SS_UNCONNECTED; } return err;}static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen, long *timeo, int flags){ struct socket *sock = sk->sk_socket; struct dn_scp *scp = DN_SK(sk); int err = -EISCONN; struct flowi fl; if (sock->state == SS_CONNECTED) goto out; if (sock->state == SS_CONNECTING) { err = 0; if (scp->state == DN_RUN) { sock->state = SS_CONNECTED; goto out; } err = -ECONNREFUSED; if (scp->state != DN_CI && scp->state != DN_CC) { sock->state = SS_UNCONNECTED; goto out; } return dn_wait_run(sk, timeo); } err = -EINVAL; if (scp->state != DN_O) goto out; if (addr == NULL || addrlen != sizeof(struct sockaddr_dn)) goto out; if (addr->sdn_family != AF_DECnet) goto out; if (addr->sdn_flags & SDF_WILD) goto out; if (sock_flag(sk, SOCK_ZAPPED)) { err = dn_auto_bind(sk->sk_socket); if (err) goto out; } memcpy(&scp->peer, addr, sizeof(struct sockaddr_dn)); err = -EHOSTUNREACH; memset(&fl, 0, sizeof(fl)); fl.oif = sk->sk_bound_dev_if; fl.fld_dst = dn_saddr2dn(&scp->peer); fl.fld_src = dn_saddr2dn(&scp->addr); dn_sk_ports_copy(&fl, scp); fl.proto = DNPROTO_NSP; if (dn_route_output_sock(&sk->sk_dst_cache, &fl, sk, flags) < 0) goto out; sk->sk_route_caps = sk->sk_dst_cache->dev->features; sock->state = SS_CONNECTING; scp->state = DN_CI; scp->segsize_loc = dst_metric(sk->sk_dst_cache, RTAX_ADVMSS); dn_nsp_send_conninit(sk, NSP_CI); err = -EINPROGRESS; if (*timeo) { err = dn_wait_run(sk, timeo); }out: return err;}static int dn_connect(struct socket *sock, struct sockaddr *uaddr, int addrlen, int flags){ struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr; struct sock *sk = sock->sk; int err; long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); lock_sock(sk); err = __dn_connect(sk, addr, addrlen, &timeo, 0); release_sock(sk); return err;}static inline int dn_check_state(struct sock *sk, struct sockaddr_dn *addr, int addrlen, long *timeo, int flags){ struct dn_scp *scp = DN_SK(sk); switch(scp->state) { case DN_RUN: return 0; case DN_CR: return dn_confirm_accept(sk, timeo, sk->sk_allocation); case DN_CI: case DN_CC: return dn_wait_run(sk, timeo); case DN_O: return __dn_connect(sk, addr, addrlen, timeo, flags); } return -EINVAL;}static void 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);}static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt){ unsigned char *ptr = skb->data; u16 len = *ptr++; /* yes, it's 8bit on the wire */ BUG_ON(len > 16); /* we've checked the contents earlier */ opt->opt_optl = dn_htons(len); opt->opt_status = 0; memcpy(opt->opt_data, ptr, len); skb_pull(skb, len + 1);}static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo){ DEFINE_WAIT(wait); struct sk_buff *skb = NULL; int err = 0; prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); for(;;) { release_sock(sk); skb = skb_dequeue(&sk->sk_receive_queue); if (skb == NULL) { *timeo = schedule_timeout(*timeo); skb = skb_dequeue(&sk->sk_receive_queue); } lock_sock(sk); if (skb != NULL) break; err = -EINVAL; if (sk->sk_state != TCP_LISTEN) break; err = sock_intr_errno(*timeo); if (signal_pending(current)) break; err = -EAGAIN; if (!*timeo) break; prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); return skb == NULL ? ERR_PTR(err) : skb;}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; long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); lock_sock(sk); if (sk->sk_state != TCP_LISTEN || DN_SK(sk)->state != DN_O) { release_sock(sk); return -EINVAL; } skb = skb_dequeue(&sk->sk_receive_queue); if (skb == NULL) { skb = dn_wait_for_connect(sk, &timeo); if (IS_ERR(skb)) { release_sock(sk); return PTR_ERR(skb); } } cb = DN_SKB_CB(skb); sk->sk_ack_backlog--; newsk = dn_alloc_sock(sk->sk_net, newsock, sk->sk_allocation); if (newsk == NULL) { release_sock(sk); kfree_skb(skb); return -ENOBUFS; } release_sock(sk); dst_release(xchg(&newsk->sk_dst_cache, skb->dst)); skb->dst = NULL; DN_SK(newsk)->state = DN_CR; DN_SK(newsk)->addrrem = cb->src_port; DN_SK(newsk)->services_rem = cb->services; DN_SK(newsk)->info_rem = cb->info; DN_SK(newsk)->segsize_rem = cb->segsize; DN_SK(newsk)->accept_mode = DN_SK(sk)->accept_mode; if (DN_SK(newsk)->segsize_rem < 230) DN_SK(newsk)->segsize_rem = 230; if ((DN_SK(newsk)->services_rem & NSP_FC_MASK) == NSP_FC_NONE) DN_SK(newsk)->max_window = decnet_no_fc_max_cwnd; newsk->sk_state = TCP_LISTEN; memcpy(&(DN_SK(newsk)->addr), &(DN_SK(sk)->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. */ DN_SK(newsk)->addr.sdn_flags &= ~SDF_WILD; skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type)); skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type)); *(__le16 *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src; *(__le16 *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst; menuver = *skb->data; skb_pull(skb, 1); if (menuver & DN_MENUVER_ACC) dn_access_copy(skb, &(DN_SK(newsk)->accessdata)); if (menuver & DN_MENUVER_USR) dn_user_copy(skb, &(DN_SK(newsk)->conndata_in)); if (menuver & DN_MENUVER_PRX) DN_SK(newsk)->peer.sdn_flags |= SDF_PROXY; if (menuver & DN_MENUVER_UIC) DN_SK(newsk)->peer.sdn_flags |= SDF_UICPROXY; kfree_skb(skb); memcpy(&(DN_SK(newsk)->conndata_out), &(DN_SK(sk)->conndata_out), sizeof(struct optdata_dn)); memcpy(&(DN_SK(newsk)->discdata_out), &(DN_SK(sk)->discdata_out), sizeof(struct optdata_dn)); lock_sock(newsk); err = dn_hash_sock(newsk); if (err == 0) { sock_reset_flag(newsk, SOCK_ZAPPED); dn_send_conn_ack(newsk); /* * Here we use sk->sk_allocation since although the conn conf is * for the newsk, the context is the old socket. */ if (DN_SK(newsk)->accept_mode == ACC_IMMED) err = dn_confirm_accept(newsk, &timeo, sk->sk_allocation); } 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 = DN_SK(sk); *uaddr_len = sizeof(struct sockaddr_dn); lock_sock(sk); if (peer) { if ((sock->state != SS_CONNECTED && sock->state != SS_CONNECTING) && scp->accept_mode == ACC_IMMED) { release_sock(sk); 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 = DN_SK(sk); int mask = datagram_poll(file, sock, wait); if (!skb_queue_empty(&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; long amount = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -