📄 udp_usrreq.c
字号:
/*
* 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*/
int
udp6_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*/
int
udp_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 void
udp_detach(inp)
struct inpcb *inp;
{
int s = splsoftnet();
in_pcbdetach(inp);
splx(s);
}
#ifdef CYGPKG_NET_SYSCTL
/*
* Sysctl for udp variables.
*/
int
udp_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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -