4ad6191c88b97d0004fb4a8d278f30e33fb865c1
/* udp_usrreq.c 6.13 85/05/27 */
#include "../net/route.h"
* UDP protocol implementation.
* Per RFC 768, August, 1980.
udb
.inp_next
= udb
.inp_prev
= &udb
;
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; */
* 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
);
struct socket
*so
= inp
->inp_socket
;
extern u_char inetctlerrmap
[];
if (cmd
< 0 || cmd
> PRC_NCMDS
)
/* these are handled by ip */
sin
= &((struct icmp
*)arg
)->icmp_ip
.ip_dst
;
in_pcbnotify(&udb
, sin
, (int)inetctlerrmap
[cmd
], udp_abort
);
register struct udpiphdr
*ui
;
register struct socket
*so
;
register struct route
*ro
;
* 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
= MAXTTL
;
if (so
->so_options
& SO_DONTROUTE
)
return (ip_output(m
, (struct mbuf
*)0, (struct route
*)0,
(so
->so_options
& SO_BROADCAST
) | IP_ROUTETOIF
));
* Use cached route for previous datagram if
* this is also to the same destination.
* NB: We don't handle broadcasts because that
* would require 3 subroutine calls.
#define satosin(sa) ((struct sockaddr_in *)(sa))
satosin(&ro
->ro_dst
)->sin_addr
.s_addr
!= ui
->ui_dst
.s_addr
) {
ro
->ro_rt
= (struct rtentry
*)0;
return (ip_output(m
, (struct mbuf
*)0, ro
,
so
->so_options
& 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
) {
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 */