udp_usrreq.c
来自「eCos操作系统源码」· C语言 代码 · 共 932 行 · 第 1/2 页
C
932 行
* subroutine of udp_input(), mainly for source code readability. * caller must properly init udp_ip6 and udp_in6 beforehand. */static voidudp_append(last, ip, n, off) struct inpcb *last; struct ip *ip; struct mbuf *n; int off;{ struct sockaddr *append_sa; struct mbuf *opts = 0;#ifdef INET6 struct ip6_recvpktopts opts6; bzero(&opts6, sizeof(opts6));#endif if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) {#ifdef INET6 if (last->inp_vflag & INP_IPV6) { int savedflags; if (udp_ip6.uip6_init_done == 0) { ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip); udp_ip6.uip6_init_done = 1; } savedflags = last->inp_flags; last->inp_flags &= ~INP_UNMAPPABLEOPTS; ip6_savecontrol(last, &udp_ip6.uip6_ip6, n, &opts6, NULL); last->inp_flags = savedflags; } else#endif ip_savecontrol(last, &opts, ip, n); }#ifdef INET6 if (last->inp_vflag & INP_IPV6) { if (udp_in6.uin6_init_done == 0) { in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin); udp_in6.uin6_init_done = 1; } append_sa = (struct sockaddr *)&udp_in6.uin6_sin; opts = opts6.head; } else#endif append_sa = (struct sockaddr *)&udp_in; m_adj(n, off); if (sbappendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) { m_freem(n); if (opts) m_freem(opts); udpstat.udps_fullsock++; } else sorwakeup(last->inp_socket);}/* * Notify a udp user of an asynchronous error; * just wake up so that he can collect error status. */voidudp_notify(inp, _errno) register struct inpcb *inp; int _errno;{ inp->inp_socket->so_error = _errno; sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket);}voidudp_ctlinput(cmd, sa, vip) int cmd; struct sockaddr *sa; void *vip;{ struct ip *ip = vip; struct udphdr *uh; void (*notify) __P((struct inpcb *, int)) = udp_notify; struct in_addr faddr; struct inpcb *inp; int s; faddr = ((struct sockaddr_in *)sa)->sin_addr; if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) return; if (PRC_IS_REDIRECT(cmd)) { ip = 0; notify = in_rtchange; } else if (cmd == PRC_HOSTDEAD) ip = 0; else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) return; if (ip) { s = splnet(); uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); inp = in_pcblookup_hash(&udbinfo, faddr, uh->uh_dport, ip->ip_src, uh->uh_sport, 0, NULL); if (inp != NULL && inp->inp_socket != NULL) (*notify)(inp, inetctlerrmap[cmd]); splx(s); } else in_pcbnotifyall(&udb, faddr, inetctlerrmap[cmd], notify);}#ifdef CYGPKG_NET_FREEBSD_SYSCTLstatic intudp_pcblist(SYSCTL_HANDLER_ARGS){ int error, i, n, s; struct inpcb *inp, **inp_list; inp_gen_t gencnt; struct xinpgen xig; /* * The process of preparing the TCB list is too time-consuming and * resource-intensive to repeat twice on every request. */ if (req->oldptr == 0) { n = udbinfo.ipi_count; req->oldidx = 2 * (sizeof xig) + (n + n/8) * sizeof(struct xinpcb); return 0; } if (req->newptr != 0) return EPERM; /* * OK, now we're committed to doing something. */ s = splnet(); gencnt = udbinfo.ipi_gencnt; n = udbinfo.ipi_count; splx(s); xig.xig_len = sizeof xig; xig.xig_count = n; xig.xig_gen = gencnt; xig.xig_sogen = so_gencnt; error = SYSCTL_OUT(req, &xig, sizeof xig); if (error) return error; inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); if (inp_list == 0) return ENOMEM; s = splnet(); for (inp = LIST_FIRST(udbinfo.listhead), i = 0; inp && i < n; inp = LIST_NEXT(inp, inp_list)) { if (inp->inp_gencnt <= gencnt) inp_list[i++] = inp; } splx(s); n = i; error = 0; for (i = 0; i < n; i++) { inp = inp_list[i]; if (inp->inp_gencnt <= gencnt) { struct xinpcb xi; xi.xi_len = sizeof xi; /* XXX should avoid extra copy */ bcopy(inp, &xi.xi_inp, sizeof *inp); if (inp->inp_socket) sotoxsocket(inp->inp_socket, &xi.xi_socket); error = SYSCTL_OUT(req, &xi, sizeof xi); } } if (!error) { /* * Give the user an updated idea of our state. * If the generation differs from what we told * her before, she knows that something happened * while we were processing this request, and it * might be necessary to retry. */ s = splnet(); xig.xig_gen = udbinfo.ipi_gencnt; xig.xig_sogen = so_gencnt; xig.xig_count = udbinfo.ipi_count; splx(s); error = SYSCTL_OUT(req, &xig, sizeof xig); } free(inp_list, M_TEMP); return error;}#endifSYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, udp_pcblist, "S,xinpcb", "List of active UDP sockets");static intudp_output(inp, m, addr, control, p) register struct inpcb *inp; struct mbuf *m; struct sockaddr *addr; struct mbuf *control; struct proc *p;{ register struct udpiphdr *ui; register int len = m->m_pkthdr.len; struct in_addr laddr; struct sockaddr_in *sin; int s = 0, error = 0; if (control) m_freem(control); /* XXX */ if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { error = EMSGSIZE; goto release; } if (addr) { sin = (struct sockaddr_in *)addr; laddr = inp->inp_laddr; if (inp->inp_faddr.s_addr != INADDR_ANY) { error = EISCONN; goto release; } /* * Must block input while temporarily connected. */ s = splnet(); error = in_pcbconnect(inp, addr, p); if (error) { splx(s); goto release; } } else { if (inp->inp_faddr.s_addr == INADDR_ANY) { error = ENOTCONN; goto release; } } /* * Calculate data length and get a mbuf * for UDP and IP headers. */ M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); if (m == 0) { error = ENOBUFS; if (addr) splx(s); goto release; } /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */ ui->ui_pr = IPPROTO_UDP; 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 = htons((u_short)len + sizeof(struct udphdr)); /* * Set up checksum and output datagram. */ if (udpcksum) { ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr, htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP)); m->m_pkthdr.csum_flags = CSUM_UDP; m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); } else { ui->ui_sum = 0; } ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ udpstat.udps_opackets++;#ifdef IPSEC if (ipsec_setsocket(m, inp->inp_socket) != 0) { error = ENOBUFS; goto release; }#endif /*IPSEC*/ error = ip_output(m, inp->inp_options, &inp->inp_route, (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)), inp->inp_moptions); if (addr) { in_pcbdisconnect(inp); inp->inp_laddr = laddr; /* XXX rehash? */ splx(s); } return (error);release: m_freem(m); return (error);}u_long udp_sendspace = 9216; /* really max datagram size */ /* 40 1K datagrams */SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, &udp_sendspace, 0, "Maximum outgoing UDP datagram size");u_long udp_recvspace = 40 * (1024 +#ifdef INET6 sizeof(struct sockaddr_in6)#else sizeof(struct sockaddr_in)#endif );SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, &udp_recvspace, 0, "Maximum incoming UDP datagram size");static intudp_abort(struct socket *so){ struct inpcb *inp; int s; inp = sotoinpcb(so); if (inp == 0) return EINVAL; /* ??? possible? panic instead? */ soisdisconnected(so); s = splnet(); in_pcbdetach(inp); splx(s); return 0;}static intudp_attach(struct socket *so, int proto, struct proc *p){ struct inpcb *inp; int s, error; inp = sotoinpcb(so); if (inp != 0) return EINVAL; error = soreserve(so, udp_sendspace, udp_recvspace); if (error) return error; s = splnet(); error = in_pcballoc(so, &udbinfo, p); splx(s); if (error) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_vflag |= INP_IPV4; inp->inp_ip_ttl = ip_defttl; return 0;}static intudp_bind(struct socket *so, struct sockaddr *nam, struct proc *p){ struct inpcb *inp; int s, error; inp = sotoinpcb(so); if (inp == 0) return EINVAL; s = splnet(); error = in_pcbbind(inp, nam, p); splx(s); return error;}static intudp_connect(struct socket *so, struct sockaddr *nam, struct proc *p){ struct inpcb *inp; int s, error; struct sockaddr_in *sin; inp = sotoinpcb(so); if (inp == 0) return EINVAL; if (inp->inp_faddr.s_addr != INADDR_ANY) return EISCONN; error = 0; s = splnet(); if (error == 0) { sin = (struct sockaddr_in *)nam; error = in_pcbconnect(inp, nam, p); } splx(s); if (error == 0) soisconnected(so); return error;}static intudp_detach(struct socket *so){ struct inpcb *inp; int s; inp = sotoinpcb(so); if (inp == 0) return EINVAL; s = splnet(); in_pcbdetach(inp); splx(s); return 0;}static intudp_disconnect(struct socket *so){ struct inpcb *inp; int s; inp = sotoinpcb(so); if (inp == 0) return EINVAL; if (inp->inp_faddr.s_addr == INADDR_ANY) return ENOTCONN; s = splnet(); in_pcbdisconnect(inp); inp->inp_laddr.s_addr = INADDR_ANY; splx(s); so->so_state &= ~SS_ISCONNECTED; /* XXX */ return 0;}static intudp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct proc *p){ struct inpcb *inp; inp = sotoinpcb(so); if (inp == 0) { m_freem(m); return EINVAL; } return udp_output(inp, m, addr, control, p);}intudp_shutdown(struct socket *so){ struct inpcb *inp; inp = sotoinpcb(so); if (inp == 0) return EINVAL; socantsendmore(so); return 0;}struct pr_usrreqs udp_usrreqs = { udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect, pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown, in_setsockaddr, sosend, soreceive, sopoll};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?