📄 udp_usrreq.c
字号:
/* * 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);}void *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;#ifdef INET6 if (sa->sa_family == AF_INET6) { if (ip) { struct ipv6 *ipv6 = (struct ipv6 *)ip; uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ipv6)); in6_pcbnotify(&udbtable, sa, uh->uh_dport, &(ipv6->ipv6_src), uh->uh_sport, cmd, udp_notify); } else in6_pcbnotify(&udbtable, sa, 0, (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify); } 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 ifnet *forceif = 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);#ifndef INET6 if (control) m_freem(control); /* XXX */#endif /* INET6 */ if (addr) { /* * 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. */ v6packet = ((inp->inp_flags & INP_IPV6) && !(inp->inp_flags & INP_IPV6_MAPPED)); if (!v6packet && control) m_freem(control); M_PREPEND(m, v6packet ? (sizeof(struct udphdr) + sizeof(struct ipv6)) : 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; } /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */#ifdef INET6 if (v6packet) { struct ipv6 *ipv6 = mtod(m, struct ipv6 *); struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) + sizeof(struct ipv6)); int payload = sizeof(struct ipv6); ipv6->ipv6_versfl = htonl(0x60000000) | (inp->inp_ipv6.ipv6_versfl & htonl(0x0fffffff)); ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit; ipv6->ipv6_nexthdr = IPPROTO_UDP; ipv6->ipv6_src = inp->inp_laddr6; ipv6->ipv6_dst = inp->inp_faddr6; ipv6->ipv6_length = (u_short)len + sizeof(struct udphdr); uh->uh_sport = inp->inp_lport; uh->uh_dport = inp->inp_fport; uh->uh_ulen = htons(ipv6->ipv6_length); uh->uh_sum = 0; if (control) if ((error = ipv6_controltoheader(&m, control, &forceif, &payload))) goto release; /* * Always calculate udp checksum for IPv6 datagrams */ if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len + sizeof(struct udphdr), payload))) uh->uh_sum = 0xffff; error = ipv6_output(m, &inp->inp_route6, inp->inp_socket->so_options & SO_DONTROUTE, (inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL, forceif, inp->inp_socket); } else#endif /* INET6 */ { ui = mtod(m, struct udpiphdr *); bzero(ui->ui_x1, sizeof ui->ui_x1); ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr)); ui->ui_src = inp->inp_laddr; ui->ui_dst = inp->inp_faddr; ui->ui_sport = inp->inp_lport; ui->ui_dport = inp->inp_fport; ui->ui_ulen = ui->ui_len; /* * Stuff checksum and output datagram. */ ui->ui_sum = 0; if (udpcksum) { if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) ui->ui_sum = 0xffff; } ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;#ifdef INET6 /* * For now, we use the default values for ttl and tos for * v4 packets sent using a v6 pcb. We probably want to * later allow v4 setsockopt operations on a v6 socket to * modify the ttl and tos for v4 packets sent using * the mapped address format. We really ought to * save the v4 ttl and v6 hoplimit in separate places * instead of craming both in the inp_hu union. */ if (inp->inp_flags & INP_IPV6) { ((struct ip *)ui)->ip_ttl = ip_defttl; ((struct ip *)ui)->ip_tos = 0; } else#endif /* INET6 */ { ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; } udpstat.udps_opackets++;#ifdef INET6 if (inp->inp_flags & INP_IPV6_MCAST) error = ip_output(m, inp->inp_options, &inp->inp_route, inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), NULL, NULL, inp->inp_socket); else#endif /* INET6 */ error = ip_output(m, inp->inp_options, &inp->inp_route, inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), inp->inp_moptions, inp, NULL); }bail: if (addr) { in_pcbdisconnect(inp); inp->inp_flags = pcbflags;#ifdef INET6 if (inp->inp_flags & INP_IPV6) inp->inp_laddr6 = laddr6; else#endif /* INET6 */ inp->inp_laddr = laddr; splx(s); } return (error);release: m_freem(m); return (error);}u_int udp_sendspace = 9216; /* really max datagram size */u_int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); /* 40 1K datagrams *//*ARGSUSED*/intudp_usrreq(so, req, m, addr, control) struct socket *so; int req; struct mbuf *m, *addr, *control;{ struct inpcb *inp = sotoinpcb(so); int error = 0; int s; if (req == PRU_CONTROL) {#ifdef INET6 if (inp->inp_flags & INP_IPV6) return (in6_control(so, (u_long)m, (caddr_t)addr, (struct ifnet *)control, 0)); else#endif /* INET6 */ return (in_control(so, (u_long)m, (caddr_t)addr, (struct ifnet *)control)); } if (inp == NULL && req != PRU_ATTACH) { error = EINVAL; goto release; } /* * Note: need to block udp_input while changing * the udp pcb queue and/or pcb addresses. */ switch (req) { case PRU_ATTACH: if (inp != NULL) { error = EINVAL; break; } s = splsoftnet(); error = in_pcballoc(so, &udbtable); splx(s); if (error) break; error = soreserve(so, udp_sendspace, udp_recvspace); if (error) break;#ifdef INET6 if (((struct inpcb *)so->so_pcb)->inp_flags & INP_IPV6) ((struct inpcb *) so->so_pcb)->inp_ipv6.ipv6_hoplimit = ipv6_defhoplmt; else#endif /* INET6 */ ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl; break; case PRU_DETACH: udp_detach(inp); break; case PRU_BIND: s = splsoftnet(); error = in_pcbbind(inp, addr); splx(s); break; case PRU_LISTEN: error = EOPNOTSUPP; break; case PRU_CONNECT:#ifdef INET6 if (inp->inp_flags & INP_IPV6) { if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) { error = EISCONN; break; } } else#endif /* INET6 */ if (inp->inp_faddr.s_addr != INADDR_ANY) { error = EISCONN; break; } s = splsoftnet(); error = in_pcbconnect(inp, addr); splx(s); if (error == 0) soisconnected(so); break; case PRU_CONNECT2: error = EOPNOTSUPP; break; case PRU_ACCEPT: error = EOPNOTSUPP; break; case PRU_DISCONNECT:#ifdef INET6 if (inp->inp_flags & INP_IPV6) { if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) { error = ENOTCONN; break; } } else#endif /* INET6 */ if (inp->inp_faddr.s_addr == INADDR_ANY) { error = ENOTCONN; break; } s = splsoftnet(); in_pcbdisconnect(inp);#ifdef INET6 if (inp->inp_flags & INP_IPV6) inp->inp_laddr6 = in6addr_any; else#endif /* INET6 */ inp->inp_laddr.s_addr = INADDR_ANY; splx(s); so->so_state &= ~SS_ISCONNECTED; /* XXX */ break; case PRU_SHUTDOWN: socantsendmore(so); break; case PRU_SEND:#ifdef IPSEC error = check_ipsec_policy(inp,0); if (error) return (error);#endif return (udp_output(m, inp, addr, control)); case PRU_ABORT: soisdisconnected(so); udp_detach(inp); break; case PRU_SOCKADDR: in_setsockaddr(inp, addr); break; case PRU_PEERADDR: in_setpeeraddr(inp, addr); break; case PRU_SENSE: /* * stat: don't bother with a blocksize. */ /* * Perhaps Path MTU might be returned for a connected * UDP socket in this case. */ return (0); case PRU_SENDOOB: case PRU_FASTTIMO: case PRU_SLOWTIMO: case PRU_PROTORCV: case PRU_PROTOSEND: error = EOPNOTSUPP; break; case PRU_RCVD: case PRU_RCVOOB: return (EOPNOTSUPP); /* do not free mbuf's */ default: panic("udp_usrreq"); }release: if (control) { printf("udp control data unexpectedly retained\n"); m_freem(control); } if (m) m_freem(m); return (error);}static voidudp_detach(inp) struct inpcb *inp;{ int s = splsoftnet(); in_pcbdetach(inp); splx(s);}/* * Sysctl for udp variables. */intudp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) int *name; u_int namelen; void *oldp; size_t *oldlenp; void *newp; size_t newlen;{ /* All sysctl names at this level are terminal. */ if (namelen != 1) return (ENOTDIR); switch (name[0]) { case UDPCTL_CHECKSUM: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); case UDPCTL_BADDYNAMIC: return (sysctl_struct(oldp, oldlenp, newp, newlen, baddynamicports.udp, sizeof(baddynamicports.udp))); case UDPCTL_RECVSPACE: return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_recvspace)); case UDPCTL_SENDSPACE: return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_sendspace)); default: return (ENOPROTOOPT); } /* NOTREACHED */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -