📄 af_decnet.c
字号:
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) queue = &scp->other_receive_queue; if (flags & MSG_WAITALL) target = size; /* * See if there is data ready to read, sleep if there isn't */ for(;;) { if (sk->err) goto out; if (skb_queue_len(&scp->other_receive_queue)) { if (!(flags & MSG_OOB)) { msg->msg_flags |= MSG_OOB; if (!scp->other_report) { scp->other_report = 1; goto out; } } } if (scp->state != DN_RUN) goto out; if (signal_pending(current)) { rv = -ERESTARTSYS; goto out; } if (dn_data_ready(sk, queue, flags, target)) break; if (flags & MSG_DONTWAIT) { rv = -EWOULDBLOCK; goto out; } set_bit(SOCK_ASYNC_WAITDATA, &sock->flags); SOCK_SLEEP_PRE(sk) if (!dn_data_ready(sk, queue, flags, target)) schedule(); SOCK_SLEEP_POST(sk) clear_bit(SOCK_ASYNC_WAITDATA, &sock->flags); } for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) { int chunk = skb->len; cb = (struct dn_skb_cb *)skb->cb; if ((chunk + copied) > size) chunk = size - copied; if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { rv = -EFAULT; break; } copied += chunk; if (!(flags & MSG_PEEK)) skb->len -= chunk; eor = cb->nsp_flags & 0x40; nskb = skb->next; if (skb->len == 0) { skb_unlink(skb); kfree_skb(skb); /* * N.B. Don't refer to skb or cb after this point * in loop. */ if ((scp->flowloc_sw == DN_DONTSEND) && !dn_congested(sk)) { scp->flowloc_sw = DN_SEND; dn_nsp_send_lnk(sk, DN_SEND); } } if (eor) { if (sk->type == SOCK_SEQPACKET) break; if (!(flags & MSG_WAITALL)) break; } if (flags & MSG_OOB) break; if (copied >= target) break; } rv = copied; if (eor && (sk->type == SOCK_SEQPACKET)) msg->msg_flags |= MSG_EOR;out: if (rv == 0) rv = (flags & MSG_PEEK) ? -sk->err : sock_error(sk); if ((rv >= 0) && msg->msg_name) { memcpy(msg->msg_name, &scp->peer, sizeof(struct sockaddr_dn)); msg->msg_namelen = sizeof(struct sockaddr_dn); } release_sock(sk); return rv;}static int dn_sendmsg(struct socket *sock, struct msghdr *msg, int size, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct dn_scp *scp = &sk->protinfo.dn; int mss = scp->mss; int mtu = 230 - 11; /* maximum value thats always safe */ struct sk_buff_head *queue = &scp->data_xmit_queue; int flags = msg->msg_flags; unsigned short numseg = 0; int err = 0; int sent = 0; int addr_len = msg->msg_namelen; struct sockaddr_dn *addr = (struct sockaddr_dn *)msg->msg_name; struct sk_buff *skb = NULL; struct dn_skb_cb *cb; unsigned char msgflg; unsigned char *ptr; unsigned short ack; int len; if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR)) return -EOPNOTSUPP; if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) return -EINVAL; if (sk->zapped && dn_auto_bind(sock)) { err = -EADDRNOTAVAIL; goto out; } if (scp->state == DN_O) { if (!addr_len || !addr) { err = -ENOTCONN; goto out; } if ((err = dn_connect(sock, (struct sockaddr *)addr, addr_len, (flags & MSG_DONTWAIT) ? O_NONBLOCK : 0)) < 0) goto out; } lock_sock(sk); if ((err = dn_wait_run(sk, flags)) < 0) goto out; if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); err = -EPIPE; goto out; } if ((flags & MSG_TRYHARD) && sk->dst_cache) dst_negative_advice(&sk->dst_cache); if (sk->dst_cache && sk->dst_cache->neighbour) { struct dn_neigh *dn = (struct dn_neigh *)sk->dst_cache->neighbour; if (dn->blksize > 230) mtu = dn->blksize - 11; } /* * The only difference between SEQPACKET & STREAM sockets under DECnet * AFAIK is that SEQPACKET sockets set the MSG_EOR flag for the last * session control message segment. */ if (flags & MSG_OOB) { mss = 16; queue = &scp->other_xmit_queue; if (size > mss) { err = -EMSGSIZE; goto out; } } if (mss < mtu) mtu = mss; scp->persist_fxn = dn_nsp_xmit_timeout; while(sent < size) { err = sock_error(sk); if (err) goto out; if (signal_pending(current)) { err = -ERESTARTSYS; goto out; } /* * Calculate size that we wish to send. */ len = size - sent; if (len > mtu) len = mtu; /* * Wait for queue size to go down below the window * size. */ if (skb_queue_len(queue) >= scp->snd_window) { if (flags & MSG_DONTWAIT) { err = -EWOULDBLOCK; goto out; } SOCK_SLEEP_PRE(sk) if (skb_queue_len(queue) >= scp->snd_window) schedule(); SOCK_SLEEP_POST(sk) continue; } /* * Get a suitably sized skb. */ skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, &err); if (err) break; if (!skb) continue; cb = (struct dn_skb_cb *)skb->cb; ptr = skb_put(skb, 9); if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; goto out; } if (flags & MSG_OOB) { cb->segnum = scp->numoth++; scp->numoth &= 0x0fff; msgflg = 0x30; ack = scp->ackxmt_oth | 0x8000; } else { cb->segnum = scp->numdat++; scp->numdat &= 0x0fff; msgflg = 0x00; if (sock->type == SOCK_STREAM) msgflg = 0x60; if (scp->seg_size == 0) msgflg |= 0x20; scp->seg_size += len; if (((sent + len) == size) && (flags & MSG_EOR)) { msgflg |= 0x40; scp->seg_size = 0; } ack = scp->ackxmt_dat | 0x8000; } *ptr++ = msgflg; *(__u16 *)ptr = scp->addrrem; ptr += 2; *(__u16 *)ptr = scp->addrloc; ptr += 2; *(__u16 *)ptr = dn_htons(ack); ptr += 2; *(__u16 *)ptr = dn_htons(cb->segnum); sent += len; dn_nsp_queue_xmit(sk, skb, flags & MSG_OOB); numseg++; skb = NULL; scp->persist = dn_nsp_persist(sk); }out: if (skb) kfree_skb(skb); release_sock(sk); return sent ? sent : err;}static int dn_device_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = (struct net_device *)ptr; switch(event) { case NETDEV_UP: dn_dev_up(dev); break; case NETDEV_DOWN: dn_dev_down(dev); break; default: break; } return NOTIFY_DONE;}static struct notifier_block dn_dev_notifier = { dn_device_event, 0};extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *);static struct packet_type dn_dix_packet_type = { __constant_htons(ETH_P_DNA_RT), NULL, /* All devices */ dn_route_rcv, (void*)1, NULL,};static int dn_get_info(char *buffer, char **start, off_t offset, int length){ struct sock *sk; struct dn_scp *scp; int len = 0; off_t pos = 0; off_t begin = 0; char buf1[DN_ASCBUF_LEN]; char buf2[DN_ASCBUF_LEN]; len += sprintf(buffer + len, "Local Remote\n"); read_lock(&dn_hash_lock); for(sk = dn_sklist; sk != NULL; sk = sk->next) { scp = &sk->protinfo.dn; len += sprintf(buffer + len, "%6s/%04X %04d:%04d %04d:%04d %01d %6s/%04X %04d:%04d %04d:%04d %01d %4s %s\n", dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1), scp->addrloc, scp->numdat, scp->numoth, scp->ackxmt_dat, scp->ackxmt_oth, scp->flowloc_sw, dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2), scp->addrrem, scp->numdat_rcv, scp->numoth_rcv, scp->ackrcv_dat, scp->ackrcv_oth, scp->flowrem_sw, dn_state2asc(scp->state), ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER")); pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > (offset + length)) break; } read_unlock(&dn_hash_lock); *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; return len;}static struct net_proto_family dn_family_ops = { AF_DECnet, dn_create};static struct proto_ops dn_proto_ops = { family: AF_DECnet, release: dn_release, bind: dn_bind, connect: dn_connect, socketpair: sock_no_socketpair, accept: dn_accept, getname: dn_getname, poll: dn_poll, ioctl: dn_ioctl, listen: dn_listen, shutdown: dn_shutdown, setsockopt: dn_setsockopt, getsockopt: dn_getsockopt, sendmsg: dn_sendmsg, recvmsg: dn_recvmsg, mmap: sock_no_mmap,};#ifdef CONFIG_SYSCTLvoid dn_register_sysctl(void);void dn_unregister_sysctl(void);#endif#ifdef MODULEEXPORT_NO_SYMBOLS;MODULE_DESCRIPTION("The Linux DECnet Network Protocol");MODULE_AUTHOR("Linux DECnet Project Team");static int addr[2] = {0, 0};MODULE_PARM(addr, "2i");MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");#endifstatic int __init decnet_init(void){#ifdef MODULE if (addr[0] > 63 || addr[0] < 0) { printk(KERN_ERR "DECnet: Area must be between 0 and 63"); return 1; } if (addr[1] > 1023 || addr[1] < 0) { printk(KERN_ERR "DECnet: Node must be between 0 and 1023"); return 1; } decnet_address = dn_htons((addr[0] << 10) | addr[1]); dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));#endif printk(KERN_INFO "NET4: DECnet for Linux: V.2.4.0-test10s (C) 1995-2000 Linux DECnet Project Team\n"); sock_register(&dn_family_ops); dev_add_pack(&dn_dix_packet_type); register_netdevice_notifier(&dn_dev_notifier); proc_net_create("decnet", 0, dn_get_info); dn_neigh_init(); dn_dev_init(); dn_route_init();#ifdef CONFIG_DECNET_ROUTER dn_fib_init();#endif /* CONFIG_DECNET_ROUTER */#ifdef CONFIG_SYSCTL dn_register_sysctl();#endif /* CONFIG_SYSCTL */ /* * Prevent DECnet module unloading until its fixed properly. * Requires an audit of the code to check for memory leaks and * initialisation problems etc. */ MOD_INC_USE_COUNT; return 0;}#ifndef MODULEstatic int __init decnet_setup(char *str){ unsigned short area = simple_strtoul(str, &str, 0); unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0); decnet_address = dn_htons(area << 10 | node); dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); return 1;}__setup("decnet=", decnet_setup);#endifstatic void __exit decnet_exit(void){ sock_unregister(AF_DECnet); dev_remove_pack(&dn_dix_packet_type);#ifdef CONFIG_SYSCTL dn_unregister_sysctl();#endif /* CONFIG_SYSCTL */ unregister_netdevice_notifier(&dn_dev_notifier); dn_route_cleanup(); dn_dev_cleanup(); dn_neigh_cleanup();#ifdef CONFIG_DECNET_ROUTER dn_fib_cleanup();#endif /* CONFIG_DECNET_ROUTER */ proc_net_remove("decnet");}module_init(decnet_init);module_exit(decnet_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -