* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)udp_usrreq.c 7.1 (Berkeley) 6/5/86
#include "../net/route.h"
* UDP protocol implementation.
* Per RFC 768, August, 1980.
udb
.inp_next
= udb
.inp_prev
= &udb
;
int udpcksum
= 0; /* XXX */
struct sockaddr_in udp_in
= { AF_INET
};
register struct udpiphdr
*ui
;
register struct inpcb
*inp
;
* Get IP and UDP header together in first mbuf.
if ((m
->m_off
> MMAXOFF
|| m
->m_len
< sizeof (struct udpiphdr
)) &&
(m
= m_pullup(m
, sizeof (struct udpiphdr
))) == 0) {
ui
= mtod(m
, struct udpiphdr
*);
if (((struct ip
*)ui
)->ip_hl
> (sizeof (struct ip
) >> 2))
ip_stripoptions((struct ip
*)ui
, (struct mbuf
*)0);
* Make mbuf data length reflect UDP length.
* If not enough data to reflect UDP length, drop.
len
= ntohs((u_short
)ui
->ui_ulen
);
if (((struct ip
*)ui
)->ip_len
!= len
) {
if (len
> ((struct ip
*)ui
)->ip_len
) {
m_adj(m
, len
- ((struct ip
*)ui
)->ip_len
);
/* ((struct ip *)ui)->ip_len = len; */
* Save a copy of the IP header in case we want restore it for ICMP.
* Checksum extended UDP header and data.
if (udpcksum
&& ui
->ui_sum
) {
ui
->ui_next
= ui
->ui_prev
= 0;
ui
->ui_len
= ui
->ui_ulen
;
if (ui
->ui_sum
= in_cksum(m
, len
+ sizeof (struct ip
))) {
* Locate pcb for datagram.
ui
->ui_src
, ui
->ui_sport
, ui
->ui_dst
, ui
->ui_dport
,
/* don't send ICMP response for broadcast packet */
if (in_broadcast(ui
->ui_dst
))
icmp_error((struct ip
*)ui
, ICMP_UNREACH
, ICMP_UNREACH_PORT
,
* Construct sockaddr format source address.
* Stuff source address and datagram in user buffer.
udp_in
.sin_port
= ui
->ui_sport
;
udp_in
.sin_addr
= ui
->ui_src
;
m
->m_len
-= sizeof (struct udpiphdr
);
m
->m_off
+= sizeof (struct udpiphdr
);
if (sbappendaddr(&inp
->inp_socket
->so_rcv
, (struct sockaddr
*)&udp_in
,
m
, (struct mbuf
*)0) == 0)
sorwakeup(inp
->inp_socket
);
* Notify a udp user of an asynchronous error;
* just wake up so that he can collect error status.
register struct inpcb
*inp
;
sorwakeup(inp
->inp_socket
);
sowwakeup(inp
->inp_socket
);
extern u_char inetctlerrmap
[];
if ((unsigned)cmd
> PRC_NCMDS
)
if (sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_IMPLINK
)
sin
= (struct sockaddr_in
*)sa
;
if (sin
->sin_addr
.s_addr
== INADDR_ANY
)
case PRC_REDIRECT_TOSNET
:
case PRC_REDIRECT_TOSHOST
:
in_pcbnotify(&udb
, &sin
->sin_addr
, 0, in_rtchange
);
if (inetctlerrmap
[cmd
] == 0)
in_pcbnotify(&udb
, &sin
->sin_addr
, (int)inetctlerrmap
[cmd
],
register struct inpcb
*inp
;
register struct udpiphdr
*ui
;
* Calculate data length and get a mbuf
* for UDP and IP headers.
for (m
= m0
; m
; m
= m
->m_next
)
MGET(m
, M_DONTWAIT
, MT_HEADER
);
* Fill in mbuf with extended UDP header
* and addresses and length put into network format.
m
->m_off
= MMAXOFF
- sizeof (struct udpiphdr
);
m
->m_len
= sizeof (struct udpiphdr
);
ui
= mtod(m
, struct udpiphdr
*);
ui
->ui_next
= ui
->ui_prev
= 0;
ui
->ui_len
= htons((u_short
)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.
if ((ui
->ui_sum
= in_cksum(m
, sizeof (struct udpiphdr
) + len
)) == 0)
((struct ip
*)ui
)->ip_len
= sizeof (struct udpiphdr
) + len
;
((struct ip
*)ui
)->ip_ttl
= UDP_TTL
;
return (ip_output(m
, inp
->inp_options
, &inp
->inp_route
,
inp
->inp_socket
->so_options
& (SO_DONTROUTE
| SO_BROADCAST
)));
int udp_sendspace
= 2048; /* really max datagram size */
int udp_recvspace
= 4 * (1024+sizeof(struct sockaddr_in
)); /* 4 1K dgrams */
udp_usrreq(so
, req
, m
, nam
, rights
)
struct mbuf
*m
, *nam
, *rights
;
struct inpcb
*inp
= sotoinpcb(so
);
return (in_control(so
, (int)m
, (caddr_t
)nam
,
(struct ifnet
*)rights
));
if (rights
&& rights
->m_len
) {
if (inp
== NULL
&& req
!= PRU_ATTACH
) {
error
= in_pcballoc(so
, &udb
);
error
= soreserve(so
, udp_sendspace
, udp_recvspace
);
error
= in_pcbbind(inp
, nam
);
if (inp
->inp_faddr
.s_addr
!= INADDR_ANY
) {
error
= in_pcbconnect(inp
, nam
);
if (inp
->inp_faddr
.s_addr
== INADDR_ANY
) {
so
->so_state
&= ~SS_ISCONNECTED
; /* XXX */
if (inp
->inp_faddr
.s_addr
!= INADDR_ANY
) {
* Must block input while temporarily connected.
error
= in_pcbconnect(inp
, nam
);
if (inp
->inp_faddr
.s_addr
== INADDR_ANY
) {
error
= udp_output(inp
, m
);
in_setsockaddr(inp
, nam
);
in_setpeeraddr(inp
, nam
);
* stat: don't bother with a blocksize.
return (EOPNOTSUPP
); /* do not free mbuf's */