f6ee5351edfd85c289fc8a05112b437efc8dda10
/* udp_usrreq.c 6.1 83/07/29 */
#include "../h/protosw.h"
#include "../h/socketvar.h"
#include "../net/route.h"
#include "../netinet/in.h"
#include "../netinet/in_pcb.h"
#include "../netinet/in_systm.h"
#include "../netinet/ip.h"
#include "../netinet/ip_var.h"
#include "../netinet/ip_icmp.h"
#include "../netinet/udp.h"
#include "../netinet/udp_var.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
, ((struct ip
*)ui
)->ip_len
- len
);
/* (struct ip *)ui->ip_len = len; */
* Checksum extended UDP header and data.
ui
->ui_next
= ui
->ui_prev
= 0;
ui
->ui_len
= htons((u_short
)len
);
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_lnaof(ui
->ui_dst
) == INADDR_ANY
)
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
;
* Calculate data length and get a mbuf
* for UDP and IP headers.
for (m
= m0
; m
; m
= m
->m_next
)
m
= m_get(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
= 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
= htons((u_short
)ui
->ui_len
);
* Stuff checksum and output datagram.
ui
->ui_sum
= in_cksum(m
, sizeof (struct udpiphdr
) + len
);
((struct ip
*)ui
)->ip_len
= sizeof (struct udpiphdr
) + len
;
((struct ip
*)ui
)->ip_ttl
= MAXTTL
;
flags
= (so
->so_options
& SO_DONTROUTE
) | (so
->so_state
& SS_PRIV
);
return (ip_output(m
, (struct mbuf
*)0, (struct route
*)0, flags
));
udp_usrreq(so
, req
, m
, nam
, rights
)
struct mbuf
*m
, *nam
, *rights
;
struct inpcb
*inp
= sotoinpcb(so
);
if (rights
&& rights
->m_len
) {
if (inp
== NULL
&& req
!= PRU_ATTACH
) {
error
= in_pcballoc(so
, &udb
);
error
= soreserve(so
, 2048, 2048);
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
) {
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
);