📄 af_decnet.c
字号:
if (flags & MSG_OOB) { if (scp->flowrem_oth == 0) return 1; } else { if (scp->flowrem_dat == 0) return 1; } } return 0;}/* * The DECnet spec requires that the "routing layer" accepts packets which * are at least 230 bytes in size. This excludes any headers which the NSP * layer might add, so we always assume that we'll be using the maximal * length header on data packets. The variation in length is due to the * inclusion (or not) of the two 16 bit acknowledgement fields so it doesn't * make much practical difference. */unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu){ unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER; if (dev) { struct dn_dev *dn_db = dev->dn_ptr; mtu -= LL_RESERVED_SPACE(dev); if (dn_db->use_long) mtu -= 21; else mtu -= 6; mtu -= DN_MAX_NSP_DATA_HEADER; } else { /* * 21 = long header, 16 = guess at MAC header length */ mtu -= (21 + DN_MAX_NSP_DATA_HEADER + 16); } if (mtu > mss) mss = mtu; return mss;}static inline unsigned int dn_current_mss(struct sock *sk, int flags){ struct dst_entry *dst = __sk_dst_get(sk); struct dn_scp *scp = DN_SK(sk); int mss_now = min_t(int, scp->segsize_loc, scp->segsize_rem); /* Other data messages are limited to 16 bytes per packet */ if (flags & MSG_OOB) return 16; /* This works out the maximum size of segment we can send out */ if (dst) { u32 mtu = dst_mtu(dst); mss_now = min_t(int, dn_mss_from_pmtu(dst->dev, mtu), mss_now); } return mss_now;}/* * N.B. We get the timeout wrong here, but then we always did get it * wrong before and this is another step along the road to correcting * it. It ought to get updated each time we pass through the routine, * but in practise it probably doesn't matter too much for now. */static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk, unsigned long datalen, int noblock, int *errcode){ struct sk_buff *skb = sock_alloc_send_skb(sk, datalen, noblock, errcode); if (skb) { skb->protocol = __constant_htons(ETH_P_DNA_RT); skb->pkt_type = PACKET_OUTGOING; } return skb;}static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size){ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); size_t mss; struct sk_buff_head *queue = &scp->data_xmit_queue; int flags = msg->msg_flags; int err = 0; size_t 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; size_t len; unsigned char fctype; long timeo; if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT)) return -EOPNOTSUPP; if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) return -EINVAL; lock_sock(sk); timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); /* * The only difference between stream sockets and sequenced packet * sockets is that the stream sockets always behave as if MSG_EOR * has been set. */ if (sock->type == SOCK_STREAM) { if (flags & MSG_EOR) { err = -EINVAL; goto out; } flags |= MSG_EOR; } err = dn_check_state(sk, addr, addr_len, &timeo, flags); if (err) goto out_err; if (sk->sk_shutdown & SEND_SHUTDOWN) { err = -EPIPE; if (!(flags & MSG_NOSIGNAL)) send_sig(SIGPIPE, current, 0); goto out_err; } if ((flags & MSG_TRYHARD) && sk->sk_dst_cache) dst_negative_advice(&sk->sk_dst_cache); mss = scp->segsize_rem; fctype = scp->services_rem & NSP_FC_MASK; mss = dn_current_mss(sk, flags); if (flags & MSG_OOB) { queue = &scp->other_xmit_queue; if (size > mss) { err = -EMSGSIZE; goto out; } } scp->persist_fxn = dn_nsp_xmit_timeout; while(sent < size) { err = sock_error(sk); if (err) goto out; if (signal_pending(current)) { err = sock_intr_errno(timeo); goto out; } /* * Calculate size that we wish to send. */ len = size - sent; if (len > mss) len = mss; /* * Wait for queue size to go down below the window * size. */ if (dn_queue_too_long(scp, queue, flags)) { if (flags & MSG_DONTWAIT) { err = -EWOULDBLOCK; goto out; } SOCK_SLEEP_PRE(sk) if (dn_queue_too_long(scp, queue, flags)) schedule(); SOCK_SLEEP_POST(sk) continue; } /* * Get a suitably sized skb. * 64 is a bit of a hack really, but its larger than any * link-layer headers and has served us well as a good * guess as to their real length. */ skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER, flags & MSG_DONTWAIT, &err); if (err) break; if (!skb) continue; cb = DN_SKB_CB(skb); skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER); if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; goto out; } if (flags & MSG_OOB) { cb->nsp_flags = 0x30; if (fctype != NSP_FC_NONE) scp->flowrem_oth--; } else { cb->nsp_flags = 0x00; if (scp->seg_total == 0) cb->nsp_flags |= 0x20; scp->seg_total += len; if (((sent + len) == size) && (flags & MSG_EOR)) { cb->nsp_flags |= 0x40; scp->seg_total = 0; if (fctype == NSP_FC_SCMC) scp->flowrem_dat--; } if (fctype == NSP_FC_SRC) scp->flowrem_dat--; } sent += len; dn_nsp_queue_xmit(sk, skb, sk->sk_allocation, flags & MSG_OOB); skb = NULL; scp->persist = dn_nsp_persist(sk); }out: if (skb) kfree_skb(skb); release_sock(sk); return sent ? sent : err;out_err: err = sk_stream_error(sk, flags, err); release_sock(sk); return err;}static int dn_device_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = (struct net_device *)ptr; if (dev->nd_net != &init_net) return NOTIFY_DONE; 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 = { .notifier_call = dn_device_event,};extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);static struct packet_type dn_dix_packet_type = { .type = __constant_htons(ETH_P_DNA_RT), .dev = NULL, /* All devices */ .func = dn_route_rcv,};#ifdef CONFIG_PROC_FSstruct dn_iter_state { int bucket;};static struct sock *dn_socket_get_first(struct seq_file *seq){ struct dn_iter_state *state = seq->private; struct sock *n = NULL; for(state->bucket = 0; state->bucket < DN_SK_HASH_SIZE; ++state->bucket) { n = sk_head(&dn_sk_hash[state->bucket]); if (n) break; } return n;}static struct sock *dn_socket_get_next(struct seq_file *seq, struct sock *n){ struct dn_iter_state *state = seq->private; n = sk_next(n);try_again: if (n) goto out; if (++state->bucket >= DN_SK_HASH_SIZE) goto out; n = sk_head(&dn_sk_hash[state->bucket]); goto try_again;out: return n;}static struct sock *socket_get_idx(struct seq_file *seq, loff_t *pos){ struct sock *sk = dn_socket_get_first(seq); if (sk) { while(*pos && (sk = dn_socket_get_next(seq, sk))) --*pos; } return *pos ? NULL : sk;}static void *dn_socket_get_idx(struct seq_file *seq, loff_t pos){ void *rc; read_lock_bh(&dn_hash_lock); rc = socket_get_idx(seq, &pos); if (!rc) { read_unlock_bh(&dn_hash_lock); } return rc;}static void *dn_socket_seq_start(struct seq_file *seq, loff_t *pos){ return *pos ? dn_socket_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *dn_socket_seq_next(struct seq_file *seq, void *v, loff_t *pos){ void *rc; if (v == SEQ_START_TOKEN) { rc = dn_socket_get_idx(seq, 0); goto out; } rc = dn_socket_get_next(seq, v); if (rc) goto out; read_unlock_bh(&dn_hash_lock);out: ++*pos; return rc;}static void dn_socket_seq_stop(struct seq_file *seq, void *v){ if (v && v != SEQ_START_TOKEN) read_unlock_bh(&dn_hash_lock);}#define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126)static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf){ int i; switch (dn_ntohs(dn->sdn_objnamel)) { case 0: sprintf(buf, "%d", dn->sdn_objnum); break; default: for (i = 0; i < dn_ntohs(dn->sdn_objnamel); i++) { buf[i] = dn->sdn_objname[i]; if (IS_NOT_PRINTABLE(buf[i])) buf[i] = '.'; } buf[i] = 0; }}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 inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk){ struct dn_scp *scp = DN_SK(sk); char buf1[DN_ASCBUF_LEN]; char buf2[DN_ASCBUF_LEN]; char local_object[DN_MAXOBJL+3]; char remote_object[DN_MAXOBJL+3]; dn_printable_object(&scp->addr, local_object); dn_printable_object(&scp->peer, remote_object); seq_printf(seq, "%6s/%04X %04d:%04d %04d:%04d %01d %-16s " "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %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, local_object, 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, remote_object, dn_state2asc(scp->state), ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));}static int dn_socket_seq_show(struct seq_file *seq, void *v){ if (v == SEQ_START_TOKEN) { seq_puts(seq, "Local Remote\n"); } else { dn_socket_format_entry(seq, v); } return 0;}static const struct seq_operations dn_socket_seq_ops = { .start = dn_socket_seq_start, .next = dn_socket_seq_next, .stop = dn_socket_seq_stop, .show = dn_socket_seq_show,};static int dn_socket_seq_open(struct inode *inode, struct file *file){ struct seq_file *seq; int rc = -ENOMEM; struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; rc = seq_open(file, &dn_socket_seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s; memset(s, 0, sizeof(*s));out: return rc;out_kfree: kfree(s); goto out;}static const struct file_operations dn_socket_seq_fops = { .owner = THIS_MODULE, .open = dn_socket_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};#endifstatic struct net_proto_family dn_family_ops = { .family = AF_DECnet, .create = dn_create, .owner = THIS_MODULE,};static const struct proto_ops dn_proto_ops = { .family = AF_DECnet, .owner = THIS_MODULE, .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, .sendpage = sock_no_sendpage,};void dn_register_sysctl(void);void dn_unregister_sysctl(void);MODULE_DESCRIPTION("The Linux DECnet Network Protocol");MODULE_AUTHOR("Linux DECnet Project Team");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_DECnet);static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n";static int __init decnet_init(void){ int rc; printk(banner); rc = proto_register(&dn_proto, 1); if (rc != 0) goto out; dn_neigh_init(); dn_dev_init(); dn_route_init(); dn_fib_init(); sock_register(&dn_family_ops); dev_add_pack(&dn_dix_packet_type); register_netdevice_notifier(&dn_dev_notifier); proc_net_fops_create(&init_net, "decnet", S_IRUGO, &dn_socket_seq_fops); dn_register_sysctl();out: return rc;}module_init(decnet_init);/* * Prevent DECnet module unloading until its fixed properly. * Requires an audit of the code to check for memory leaks and * initialisation problems etc. */#if 0static void __exit decnet_exit(void){ sock_unregister(AF_DECnet); rtnl_unregister_all(PF_DECnet); dev_remove_pack(&dn_dix_packet_type); dn_unregister_sysctl(); unregister_netdevice_notifier(&dn_dev_notifier); dn_route_cleanup(); dn_dev_cleanup(); dn_neigh_cleanup(); dn_fib_cleanup(); proc_net_remove(&init_net, "decnet"); proto_unregister(&dn_proto);}module_exit(decnet_exit);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -