udp_usrreq.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,375 行 · 第 1/3 页
C
1,375 行
/* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */#ifdef INET6 if (v6packet) { struct ip6_hdr *ipv6 = mtod(m, struct ip6_hdr *); struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) + sizeof(struct ip6_hdr)); int payload = sizeof(struct ip6_hdr); struct in6_addr *faddr; struct in6_addr *laddr; struct ifnet *oifp = NULL; ipv6->ip6_flow = htonl(0x60000000) | (inp->inp_ipv6.ip6_flow & htonl(0x0fffffff)); ipv6->ip6_nxt = IPPROTO_UDP; ipv6->ip6_dst = inp->inp_faddr6; /* * If the scope of the destination is link-local, * embed the interface * index in the address. * * XXX advanced-api value overrides sin6_scope_id */ faddr = &ipv6->ip6_dst; if (IN6_IS_ADDR_LINKLOCAL(faddr) || IN6_IS_ADDR_MC_LINKLOCAL(faddr)) { struct ip6_pktopts *optp = inp->inp_outputopts6; struct in6_pktinfo *pi = NULL; struct ip6_moptions *mopt = NULL; /* * XXX Boundary check is assumed to be already done in * ip6_setpktoptions(). */ if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) { faddr->s6_addr16[1] = htons(pi->ipi6_ifindex); oifp = ifindex2ifnet[pi->ipi6_ifindex]; } else if (IN6_IS_ADDR_MULTICAST(faddr) && (mopt = inp->inp_moptions6) && mopt->im6o_multicast_ifp) { oifp = mopt->im6o_multicast_ifp; faddr->s6_addr16[1] = oifp->if_index; } else if (sin6 && sin6->sin6_scope_id) { /* boundary check */ if (sin6->sin6_scope_id < 0 || if_index < sin6->sin6_scope_id) { error = ENXIO; /* XXX EINVAL? */ goto release; } /* XXX */ faddr->s6_addr16[1] = htons(sin6->sin6_scope_id & 0xffff); } } ipv6->ip6_hlim = in6_selecthlim(inp, oifp); if (sin6) { /*XXX*/ laddr = in6_selectsrc(sin6, inp->inp_outputopts6, inp->inp_moptions6, &inp->inp_route6, &inp->inp_laddr6, &error); if (laddr == NULL) { if (error == 0) error = EADDRNOTAVAIL; goto release; } } else laddr = &inp->inp_laddr6; ipv6->ip6_src = *laddr; ipv6->ip6_plen = (u_short)len + sizeof(struct udphdr); uh->uh_sport = inp->inp_lport; uh->uh_dport = inp->inp_fport; uh->uh_ulen = htons(ipv6->ip6_plen); uh->uh_sum = 0; /* * Always calculate udp checksum for IPv6 datagrams */ if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP, payload, len + sizeof(struct udphdr)))) uh->uh_sum = 0xffff; error = ip6_output(m, inp->inp_outputopts6, &inp->inp_route6, inp->inp_socket->so_options & SO_DONTROUTE, (inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL, NULL); } 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 inp->inp_laddr = laddr; splx(s); } if (control) {#ifdef INET6 if (v6packet) inp->inp_outputopts6 = stickyopt;#endif m_freem(control); } return (error);release: m_freem(m); if (control) {#ifdef INET6 if (v6packet) inp->inp_outputopts6 = stickyopt;#endif m_freem(control); } return (error);}u_int udp_sendspace = 9216; /* really max datagram size */u_int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); /* 40 1K datagrams */#if defined(INET6) && !defined(TCP6)/*ARGSUSED*/intudp6_usrreq(so, req, m, addr, control, p) struct socket *so; int req; struct mbuf *m, *addr, *control; struct proc *p;{ return udp_usrreq(so, req, m, addr, control);}#endif/*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.ip6_hlim = ip6_defhlim; 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();#ifdef INET6 if (inp->inp_flags & INP_IPV6) error = in6_pcbbind(inp, addr); else#endif 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; } s = splsoftnet(); error = in6_pcbconnect(inp, addr); splx(s); } 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:#ifdef INET6 if (inp->inp_flags & INP_IPV6) in6_setsockaddr(inp, addr); else#endif /* INET6 */ in_setsockaddr(inp, addr); break; case PRU_PEERADDR:#ifdef INET6 if (inp->inp_flags & INP_IPV6) in6_setpeeraddr(inp, addr); else#endif /* INET6 */ 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) {#ifdef __ECOS diag_printf("udp control data unexpectedly retained\n");#else printf("udp control data unexpectedly retained\n");#endif 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);}#ifdef CYGPKG_NET_SYSCTL/* * 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 */}#endif // CYGPKG_NET_SYSCTL
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?