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 + -
显示快捷键?