static char rcsident
[] = "$Header: udp.c,v 1.18 85/07/31 09:44:10 walsh Exp $";
#include "../h/socketvar.h"
#include "../net/route.h"
#include "../bbnnet/in.h"
#include "../bbnnet/in_var.h"
#include "../bbnnet/net.h"
#include "../bbnnet/ip.h"
#include "../bbnnet/udp.h"
#include "../bbnnet/in_pcb.h"
#include "../bbnnet/icmp.h"
#include "../bbnnet/hmp_traps.h"
static char rcsudphdr
[] = RCSUDPHDR
;
* Process incoming udp messages. Called directly from ip_input.
* User sees udp header with pseudo-header which overlays ip header
register struct mbuf
*mp
;
register struct inpcb
*inp
;
register u_short i
, j
, ulen
;
if ((mp
->m_off
> MMAXOFF
) || (mp
->m_len
< sizeof(struct udp
)))
if ((mp
= m_pullup(mp
, sizeof(struct udp
))) == NULL
)
p
= mtod(mp
, struct udp
*);
ulen
= ((struct ip
*) p
) ->ip_len
; /* ip_input() set to amt IP data */
mp
->m_off
+= sizeof p
->u_x
;
mp
->m_len
-= sizeof p
->u_x
;
if (ntohs(p
->u_len
) != ulen
)
* u_ilen overlays IP checksum, which is now zero.
* ulen is the actual number of bytes we got on input
* from IP; u_len is what UDP says we should have
* (sizeof(udp_specific) + datalen)
log(LOG_WARNING
, "UDP len %d, but got %d\n", ntohs(p
->u_len
), ulen
);
* Do checksum calculation. Assumes pseudo-header passed up from
* IP level and finished above.
* Zero checksum on send means no checksum was generated.
j
= (u_short
) in_cksum(mp
, (int) (ulen
+ UDPCKSIZE
));
* Remember that zero is special, and compensate for this.
/* hmp_trap(T_UDP_CKSUM, (caddr_t)0,0); */
inet_cksum_err ("udp", (struct ip
*) p
, (u_long
) i
, (u_long
) j
);
inp
= in_pcblookup(&udp
, p
->u_s
.s_addr
, (u_short
)0,
p
->u_d
.s_addr
, p
->u_dst
, TRUE
);
/* if a user is found, queue the data, otherwise drop it */
struct sockaddr_in udpsock
;
* throw away entire IP and UDP leaders.
* user gets address separately.
mp
->m_off
+= sizeof (struct udp
) - sizeof (p
->u_x
);
mp
->m_len
-= sizeof (struct udp
) - sizeof (p
->u_x
);
udpsock
.sin_family
= AF_INET
;
udpsock
.sin_port
= p
->u_src
;
udpsock
.sin_addr
= p
->u_s
;
udpsock
.sin_zero
[0] = udpsock
.sin_zero
[1] = 0;
sorcv
= &inp
->inp_socket
->so_rcv
;
if (! sbappendaddr(sorcv
, (struct sockaddr
*)&udpsock
, mp
,
if ((ulen
- UDPSIZE
+ sizeof(struct sockaddr
)) > sbspace(sorcv
))
sorwakeup(inp
->inp_socket
);
* No one wants this packet.
if (!in_broadcast(p
->u_s
) && !in_broadcast(p
->u_d
))
* Don't bother everyone on the net. Someone else may
* provide the service (port).
ic_errmsg (icmp_addr((struct ip
*) p
), p
->u_s
,
ICMP_UNRCH
, ICMP_UNRCH_PORT
, 0,
sizeof(struct ip
) + ICMP_ERRLEN
, (char *) p
);
* Output a udp message. Called from udp_usrreq().
register struct mbuf
*mp
;
for (m
= mp
; m
; m
= m
->m_next
)
* find a place to put the IP/UDP headers.
m
= m_get(M_WAIT
, MT_HEADER
);
* Compose header in first mbuf. Get addresses and ports
* from ucb, add in pseudo-header fields for checksum.
* Ensure header is aligned for memory access speed...
mp
->m_off
= (MMAXOFF
- sizeof(struct udp
)) & ~(sizeof(long) -1);
mp
->m_len
= sizeof(struct udp
);
p
= mtod(mp
, struct udp
*);
p
->u_src
= inp
->inp_lport
;
p
->u_dst
= inp
->inp_fport
;
p
->u_len
= htons((u_short
)len
+UDPSIZE
);
((struct ip
*) p
)->ip_tos
= 0; /* for ip_send() */
/* Do checksum. Include pseudo header. */
mp
->m_off
+= sizeof p
->u_x
;
mp
->m_len
-= sizeof p
->u_x
;
p
->u_sum
= in_cksum(mp
, len
+ sizeof(struct udp
) - sizeof p
->u_x
);
/* Zero is reserved for unsummed packets */
mp
->m_off
-= sizeof p
->u_x
;
mp
->m_len
+= sizeof p
->u_x
;
* Now send the packet via IP.
return(ip_send(inp
, mp
, len
+UDPSIZE
, FALSE
));