udp_usrreq.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,375 行 · 第 1/3 页
C
1,375 行
inp->inp_fport != uh->uh_sport) continue; } else#endif /* INET6 */ if (inp->inp_faddr.s_addr != INADDR_ANY) { if (inp->inp_faddr.s_addr != ip->ip_src.s_addr || inp->inp_fport != uh->uh_sport) continue; } if (last != NULL) { struct mbuf *n; if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { opts = NULL;#ifdef INET6 if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS)) ip6_savecontrol(inp, &opts, ipv6, n);#endif /* INET6 */ m_adj(n, iphlen); if (sbappendaddr(&last->so_rcv,#ifdef INET6 /* * This cruft is needed in (the rare) * case I deliver a {multi,broad}cast * IPv4 packet to an AF_INET6 socket. */ ((((struct inpcb *)last->so_pcb)->inp_flags & INP_IPV6) && ip) ? (struct sockaddr *)&src_v4mapped :#endif /* INET6 */ &srcsa.sa, n, opts) == 0) { m_freem(n); udpstat.udps_fullsock++; } else sorwakeup(last); } } last = inp->inp_socket; /* * Don't look for additional matches if this one does * not have either the SO_REUSEPORT or SO_REUSEADDR * socket options set. This heuristic avoids searching * through all pcbs in the common case of a non-shared * port. It * assumes that an application will never * clear these options after setting them. */ if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) break; } if (last == NULL) { /* * No matching pcb found; discard datagram. * (No need to send an ICMP Port Unreachable * for a broadcast or multicast datgram.) */ udpstat.udps_noportbcast++; goto bad; } opts = NULL;#ifdef INET6 if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS)) ip6_savecontrol(inp, &opts, ipv6, m);#endif /* INET6 */ m_adj(m, iphlen); if (sbappendaddr(&last->so_rcv, #ifdef INET6 /* * This cruft is needed in (the rare) case I * deliver a {multi,broad}cast IPv4 packet to * an AF_INET6 socket. */ ((((struct inpcb *)last->so_pcb)->inp_flags & INP_IPV6) && ip) ? (struct sockaddr *)&src_v4mapped :#endif /* INET6 */ &srcsa.sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } sorwakeup(last); return; } /* * Locate pcb for datagram. */#ifdef INET6 if (ipv6) inp = in6_pcbhashlookup(&udbtable, &ipv6->ip6_src, uh->uh_sport, &ipv6->ip6_dst, uh->uh_dport); else#endif /* INET6 */ inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport); if (inp == 0) { ++udpstat.udps_pcbhashmiss;#ifdef INET6 if (ipv6) { inp = in_pcblookup(&udbtable, (struct in_addr *)&(ipv6->ip6_src), uh->uh_sport, (struct in_addr *)&(ipv6->ip6_dst), uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6); } else#endif /* INET6 */ inp = in_pcblookup(&udbtable, &ip->ip_src, uh->uh_sport, &ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); if (inp == 0) { udpstat.udps_noport++; if (m->m_flags & (M_BCAST | M_MCAST)) { udpstat.udps_noportbcast++; goto bad; }#ifdef INET6 if (ipv6) { icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT,0); } else#endif /* INET6 */ { *ip = save_ip; HTONS(ip->ip_len); HTONS(ip->ip_id); HTONS(ip->ip_off); uh->uh_sum = savesum; icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); } return; } }#ifdef IPSEC /* Check if this socket requires security for incoming packets */ if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE && !(m->m_flags & M_AUTH)) || (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE && !(m->m_flags & M_CONF))) {#ifdef notyet#ifdef INET6 if (ipv6) ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0); else#endif /* INET6 */ icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0); m = NULL;#endif /* notyet */ udpstat.udps_nosec++; goto bad; } /* Use tdb_bind_out for this inp's outbound communication */ if (tdb) tdb_add_inp(tdb, inp);#endif /*IPSEC */ opts = NULL;#ifdef INET6 if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS)) ip6_savecontrol(inp, &opts, ipv6, m);#endif /* INET6 */ if (ip && (inp->inp_flags & INP_CONTROLOPTS)) { struct mbuf **mp = &opts; if (inp->inp_flags & INP_RECVDSTADDR) { *mp = udp_saveopt((caddr_t) &ip->ip_dst, sizeof(struct in_addr), IP_RECVDSTADDR); if (*mp) mp = &(*mp)->m_next; }#ifdef notyet /* options were tossed above */ if (inp->inp_flags & INP_RECVOPTS) { *mp = udp_saveopt((caddr_t) opts_deleted_above, sizeof(struct in_addr), IP_RECVOPTS); if (*mp) mp = &(*mp)->m_next; } /* ip_srcroute doesn't do what we want here, need to fix */ if (inp->inp_flags & INP_RECVRETOPTS) { *mp = udp_saveopt((caddr_t) ip_srcroute(), sizeof(struct in_addr), IP_RECVRETOPTS); if (*mp) mp = &(*mp)->m_next; }#endif } iphlen += sizeof(struct udphdr); m_adj(m, iphlen); if (sbappendaddr(&inp->inp_socket->so_rcv,#ifdef INET6 /* * This cruft is needed to deliver a IPv4 packet to * an AF_INET6 socket. */ ((((struct inpcb *)inp->inp_socket->so_pcb)->inp_flags & INP_IPV6) && ip) ? (struct sockaddr *)&src_v4mapped : #endif /* INET6 */ &srcsa.sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } sorwakeup(inp->inp_socket); return;bad: m_freem(m); if (opts) m_freem(opts);}/* * Create a "control" mbuf containing the specified data * with the specified type for presentation with a datagram. */struct mbuf *udp_saveopt(p, size, type) caddr_t p; register int size; int type;{ register struct cmsghdr *cp; struct mbuf *m; if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) return ((struct mbuf *) NULL); cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); bcopy(p, CMSG_DATA(cp), size); size += sizeof(*cp); m->m_len = size; cp->cmsg_len = size; cp->cmsg_level = IPPROTO_IP; cp->cmsg_type = type; return (m);}/* * Notify a udp user of an asynchronous error; * just wake up so that he can collect error status. */static voidudp_notify(inp, errno) register struct inpcb *inp; int errno;{ inp->inp_socket->so_error = errno; sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket);}#if defined(INET6) && !defined(TCP6)voidudp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; void *d;{ struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off; if (sa == NULL) return; if (sa->sa_family != AF_INET6) return; /* decode parameter from icmp6. */ if (d != NULL) { struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; ip6 = ip6cp->ip6c_ip6; m = ip6cp->ip6c_m; off = ip6cp->ip6c_off; } else return; /* translate addresses into internal form */ sa6 = *(struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); sa = (struct sockaddr *)&sa6; (void)udp_ctlinput(cmd, sa, (void *)ip6);}#endifvoid *udp_ctlinput(cmd, sa, v) int cmd; struct sockaddr *sa; void *v;{ register struct ip *ip = v; register struct udphdr *uh; extern int inetctlerrmap[]; void (*notify) __P((struct inpcb *, int)) = udp_notify; int errno; if ((unsigned)cmd >= PRC_NCMDS) return NULL; errno = inetctlerrmap[cmd]; if (PRC_IS_REDIRECT(cmd)) notify = in_rtchange, ip = 0; else if (cmd == PRC_HOSTDEAD) ip = 0; else if (errno == 0) return NULL; if (sa == NULL) return NULL;#ifdef INET6 if (sa->sa_family == AF_INET6) { if (ip) { struct ip6_hdr *ipv6 = (struct ip6_hdr *)ip; uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ip6_hdr));#if 0 /*XXX*/ in6_pcbnotify(&udbtable, sa, uh->uh_dport, &(ipv6->ip6_src), uh->uh_sport, cmd, udp_notify);#endif } else {#if 0 /*XXX*/ in6_pcbnotify(&udbtable, sa, 0, (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);#endif } } else#endif /* INET6 */ if (ip) { uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); in_pcbnotify(&udbtable, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, errno, notify); } else in_pcbnotifyall(&udbtable, sa, errno, notify); return NULL;}int#if __STDC__udp_output(struct mbuf *m, ...)#elseudp_output(m, va_alist) struct mbuf *m; va_dcl#endif{ register struct inpcb *inp; struct mbuf *addr, *control; register struct udpiphdr *ui; register int len = m->m_pkthdr.len; struct in_addr laddr; int s = 0, error = 0; va_list ap;#ifdef INET6 register struct in6_addr laddr6; int v6packet = 0; struct sockaddr_in6 *sin6 = NULL; struct ip6_pktopts opt, *stickyopt = NULL;#endif /* INET6 */ int pcbflags = 0; va_start(ap, m); inp = va_arg(ap, struct inpcb *); addr = va_arg(ap, struct mbuf *); control = va_arg(ap, struct mbuf *); va_end(ap);#ifdef INET6 v6packet = ((inp->inp_flags & INP_IPV6) && !(inp->inp_flags & INP_IPV6_MAPPED));#endif#ifdef INET6 stickyopt = inp->inp_outputopts6; if (control && v6packet) { error = ip6_setpktoptions(control, &opt, ((inp->inp_socket->so_state & SS_PRIV) != 0)); if (error != 0) goto release; inp->inp_outputopts6 = &opt; }#endif if (addr) {#ifdef INET6 sin6 = mtod(addr, struct sockaddr_in6 *);#endif /* * Save current PCB flags because they may change during * temporary connection, particularly the INP_IPV6_UNDEC * flag. */ pcbflags = inp->inp_flags;#ifdef INET6 if (inp->inp_flags & INP_IPV6) laddr6 = inp->inp_laddr6; else#endif /* INET6 */ laddr = inp->inp_laddr;#ifdef INET6 if (((inp->inp_flags & INP_IPV6) && !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) || (inp->inp_faddr.s_addr != INADDR_ANY))#else /* INET6 */ if (inp->inp_faddr.s_addr != INADDR_ANY)#endif /* INET6 */ { error = EISCONN; goto release; } /* * Must block input while temporarily connected. */ s = splsoftnet(); error = in_pcbconnect(inp, addr); if (error) { splx(s); goto release; } } else {#ifdef INET6 if (((inp->inp_flags & INP_IPV6) && IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) || (inp->inp_faddr.s_addr == INADDR_ANY))#else /* INET6 */ if (inp->inp_faddr.s_addr == INADDR_ANY)#endif /* INET6 */ { error = ENOTCONN; goto release; } } /* * Calculate data length and get a mbuf * for UDP and IP headers. */#ifdef INET6 /* * Handles IPv4-mapped IPv6 address because temporary connect sets * the right flag. */ M_PREPEND(m, v6packet ? (sizeof(struct udphdr) + sizeof(struct ip6_hdr)) : sizeof(struct udpiphdr), M_DONTWAIT);#else /* INET6 */ M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);#endif /* INET6 */ if (m == 0) { error = ENOBUFS; goto bail; } /* * Compute the packet length of the IP header, and * punt if the length looks bogus. */ if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) { error = EMSGSIZE; goto release; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?