📄 udp.c
字号:
/* process the ESP packet */ ret = xfrm4_rcv_encap(skb, up->encap_type); UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); return -ret; } /* FALLTHROUGH -- it's a UDP Packet */ } if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if (__udp_checksum_complete(skb)) { UDP_INC_STATS_BH(UDP_MIB_INERRORS); kfree_skb(skb); return -1; } skb->ip_summed = CHECKSUM_UNNECESSARY; } if (sock_queue_rcv_skb(sk,skb)<0) { UDP_INC_STATS_BH(UDP_MIB_INERRORS); kfree_skb(skb); return -1; } UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); return 0;}/* * Multicasts and broadcasts go to each listener. * * Note: called only from the BH handler context, * so we don't need to lock the hashes. */static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, u32 saddr, u32 daddr){ struct sock *sk; int dif; read_lock(&udp_hash_lock); sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); dif = skb->dev->ifindex; sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (sk) { struct sock *sknext = NULL; do { struct sk_buff *skb1 = skb; sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, uh->source, saddr, dif); if(sknext) skb1 = skb_clone(skb, GFP_ATOMIC); if(skb1) { int ret = udp_queue_rcv_skb(sk, skb1); if (ret > 0) /* we should probably re-process instead * of dropping packets here. */ kfree_skb(skb1); } sk = sknext; } while(sknext); } else kfree_skb(skb); read_unlock(&udp_hash_lock); return 0;}/* Initialize UDP checksum. If exited with zero value (success), * CHECKSUM_UNNECESSARY means, that no more checks are required. * Otherwise, csum completion requires chacksumming packet body, * including udp header and folding it to skb->csum. */static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, unsigned short ulen, u32 saddr, u32 daddr){ if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed == CHECKSUM_HW) { skb->ip_summed = CHECKSUM_UNNECESSARY; if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) return 0; NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp v4 hw csum failure.\n")); skb->ip_summed = CHECKSUM_NONE; } if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); /* Probably, we should checksum udp header (it should be in cache * in any case) and data in tiny packets (< rx copybreak). */ return 0;}/* * All we need to do is get the socket, and then do a checksum. */ int udp_rcv(struct sk_buff *skb){ struct sock *sk; struct udphdr *uh; unsigned short ulen; struct rtable *rt = (struct rtable*)skb->dst; u32 saddr = skb->nh.iph->saddr; u32 daddr = skb->nh.iph->daddr; int len = skb->len; /* * Validate the packet and the UDP length. */ if (!pskb_may_pull(skb, sizeof(struct udphdr))) goto no_header; uh = skb->h.uh; ulen = ntohs(uh->len); if (ulen > len || ulen < sizeof(*uh)) goto short_packet; if (pskb_trim(skb, ulen)) goto short_packet; if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0) goto csum_error; if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) return udp_v4_mcast_deliver(skb, uh, saddr, daddr); sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); if (sk != NULL) { int ret = udp_queue_rcv_skb(sk, skb); sock_put(sk); /* a return value > 0 means to resubmit the input, but * it it wants the return to be -protocol, or 0 */ if (ret > 0) return -ret; return 0; } if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto drop; /* No socket. Drop packet silently, if checksum is wrong */ if (udp_checksum_complete(skb)) goto csum_error; UDP_INC_STATS_BH(UDP_MIB_NOPORTS); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* * Hmm. We got an UDP packet to a port to which we * don't wanna listen. Ignore it. */ kfree_skb(skb); return(0);short_packet: NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", NIPQUAD(saddr), ntohs(uh->source), ulen, len, NIPQUAD(daddr), ntohs(uh->dest)));no_header: UDP_INC_STATS_BH(UDP_MIB_INERRORS); kfree_skb(skb); return(0);csum_error: /* * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", NIPQUAD(saddr), ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest), ulen));drop: UDP_INC_STATS_BH(UDP_MIB_INERRORS); kfree_skb(skb); return(0);}static int udp_destroy_sock(struct sock *sk){ lock_sock(sk); udp_flush_pending_frames(sk); release_sock(sk); return 0;}/* * Socket option code for UDP */static int udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen){ struct udp_opt *up = udp_sk(sk); int val; int err = 0; if (level != SOL_UDP) return ip_setsockopt(sk, level, optname, optval, optlen); if(optlen<sizeof(int)) return -EINVAL; if (get_user(val, (int __user *)optval)) return -EFAULT; switch(optname) { case UDP_CORK: if (val != 0) { up->corkflag = 1; } else { up->corkflag = 0; lock_sock(sk); udp_push_pending_frames(sk, up); release_sock(sk); } break; case UDP_ENCAP: switch (val) { case 0: case UDP_ENCAP_ESPINUDP: case UDP_ENCAP_ESPINUDP_NON_IKE: up->encap_type = val; break; default: err = -ENOPROTOOPT; break; } break; default: err = -ENOPROTOOPT; break; }; return err;}static int udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen){ struct udp_opt *up = udp_sk(sk); int val, len; if (level != SOL_UDP) return ip_getsockopt(sk, level, optname, optval, optlen); if(get_user(len,optlen)) return -EFAULT; len = min_t(unsigned int, len, sizeof(int)); if(len < 0) return -EINVAL; switch(optname) { case UDP_CORK: val = up->corkflag; break; case UDP_ENCAP: val = up->encap_type; break; default: return -ENOPROTOOPT; }; if(put_user(len, optlen)) return -EFAULT; if(copy_to_user(optval, &val,len)) return -EFAULT; return 0;}struct proto udp_prot = { .name = "UDP", .close = udp_close, .connect = ip4_datagram_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, .destroy = udp_destroy_sock, .setsockopt = udp_setsockopt, .getsockopt = udp_getsockopt, .sendmsg = udp_sendmsg, .recvmsg = udp_recvmsg, .sendpage = udp_sendpage, .backlog_rcv = udp_queue_rcv_skb, .hash = udp_v4_hash, .unhash = udp_v4_unhash, .get_port = udp_v4_get_port, .slab_obj_size = sizeof(struct udp_sock),};/* ------------------------------------------------------------------------ */#ifdef CONFIG_PROC_FSstatic struct sock *udp_get_first(struct seq_file *seq){ struct sock *sk; struct udp_iter_state *state = seq->private; for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; sk_for_each(sk, node, &udp_hash[state->bucket]) { if (sk->sk_family == state->family) goto found; } } sk = NULL;found: return sk;}static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk){ struct udp_iter_state *state = seq->private; do { sk = sk_next(sk);try_again: ; } while (sk && sk->sk_family != state->family); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(&udp_hash[state->bucket]); goto try_again; } return sk;}static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos){ struct sock *sk = udp_get_first(seq); if (sk) while(pos && (sk = udp_get_next(seq, sk)) != NULL) --pos; return pos ? NULL : sk;}static void *udp_seq_start(struct seq_file *seq, loff_t *pos){ read_lock(&udp_hash_lock); return *pos ? udp_get_idx(seq, *pos-1) : (void *)1;}static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct sock *sk; if (v == (void *)1) sk = udp_get_idx(seq, 0); else sk = udp_get_next(seq, v); ++*pos; return sk;}static void udp_seq_stop(struct seq_file *seq, void *v){ read_unlock(&udp_hash_lock);}static int udp_seq_open(struct inode *inode, struct file *file){ struct udp_seq_afinfo *afinfo = PDE(inode)->data; struct seq_file *seq; int rc = -ENOMEM; struct udp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; memset(s, 0, sizeof(*s)); s->family = afinfo->family; s->seq_ops.start = udp_seq_start; s->seq_ops.next = udp_seq_next; s->seq_ops.show = afinfo->seq_show; s->seq_ops.stop = udp_seq_stop; rc = seq_open(file, &s->seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s;out: return rc;out_kfree: kfree(s); goto out;}/* ------------------------------------------------------------------------ */int udp_proc_register(struct udp_seq_afinfo *afinfo){ struct proc_dir_entry *p; int rc = 0; if (!afinfo) return -EINVAL; afinfo->seq_fops->owner = afinfo->owner; afinfo->seq_fops->open = udp_seq_open; afinfo->seq_fops->read = seq_read; afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = seq_release_private; p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else rc = -ENOMEM; return rc;}void udp_proc_unregister(struct udp_seq_afinfo *afinfo){ if (!afinfo) return; proc_net_remove(afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));}/* ------------------------------------------------------------------------ */static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket){ struct inet_opt *inet = inet_sk(sp); unsigned int dest = inet->daddr; unsigned int src = inet->rcv_saddr; __u16 destp = ntohs(inet->dport); __u16 srcp = ntohs(inet->sport); sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", bucket, src, srcp, dest, destp, sp->sk_state, atomic_read(&sp->sk_wmem_alloc), atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->sk_refcnt), sp);}static int udp4_seq_show(struct seq_file *seq, void *v){ if (v == SEQ_START_TOKEN) seq_printf(seq, "%-127s\n", " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout " "inode"); else { char tmpbuf[129]; struct udp_iter_state *state = seq->private; udp4_format_sock(v, tmpbuf, state->bucket); seq_printf(seq, "%-127s\n", tmpbuf); } return 0;}/* ------------------------------------------------------------------------ */static struct file_operations udp4_seq_fops;static struct udp_seq_afinfo udp4_seq_afinfo = { .owner = THIS_MODULE, .name = "udp", .family = AF_INET, .seq_show = udp4_seq_show, .seq_fops = &udp4_seq_fops,};int __init udp4_proc_init(void){ return udp_proc_register(&udp4_seq_afinfo);}void udp4_proc_exit(void){ udp_proc_unregister(&udp4_seq_afinfo);}#endif /* CONFIG_PROC_FS */EXPORT_SYMBOL(udp_disconnect);EXPORT_SYMBOL(udp_hash);EXPORT_SYMBOL(udp_hash_lock);EXPORT_SYMBOL(udp_ioctl);EXPORT_SYMBOL(udp_port_rover);EXPORT_SYMBOL(udp_prot);EXPORT_SYMBOL(udp_sendmsg);#ifdef CONFIG_PROC_FSEXPORT_SYMBOL(udp_proc_register);EXPORT_SYMBOL(udp_proc_unregister);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -