xref: /csrg-svn/sys/deprecated/bbnnet/udp.c (revision 25216)
125202Skarels #ifdef RCSIDENT
225202Skarels static char rcsident[] = "$Header: udp.c,v 1.18 85/07/31 09:44:10 walsh Exp $";
325202Skarels #endif
425202Skarels 
525202Skarels 
625202Skarels #include "../h/param.h"
725202Skarels #include "../h/systm.h"
825202Skarels #include "../h/dir.h"
925202Skarels #include "../h/user.h"
1025202Skarels #include "../h/mbuf.h"
1125202Skarels #include "../h/socket.h"
1225202Skarels #include "../h/socketvar.h"
1325202Skarels #include "../h/syslog.h"
1425202Skarels 
1525202Skarels #include "../net/if.h"
1625202Skarels #include "../net/route.h"
1725202Skarels 
1825202Skarels #include "../bbnnet/in.h"
1925202Skarels #include "../bbnnet/in_var.h"
2025202Skarels #include "../bbnnet/net.h"
2125202Skarels #include "../bbnnet/ip.h"
2225202Skarels #include "../bbnnet/udp.h"
2325202Skarels #include "../bbnnet/in_pcb.h"
2425202Skarels #include "../bbnnet/icmp.h"
2525202Skarels #ifdef HMPTRAPS
2625202Skarels #include "../bbnnet/hmp_traps.h"
2725202Skarels #endif
2825202Skarels 
2925202Skarels #ifdef RCSIDENT
3025202Skarels static char rcsudphdr[] = RCSUDPHDR;
3125202Skarels #endif
3225202Skarels 
3325202Skarels extern int nosum;
3425202Skarels 
3525202Skarels struct inpcb udp;
3625202Skarels struct udp_stat udpstat;
3725202Skarels 
3825202Skarels /*
3925202Skarels  *  Process incoming udp messages.  Called directly from ip_input.
4025202Skarels  *  User sees udp header with pseudo-header which overlays ip header
4125202Skarels  *  (defined in udp.h).
4225202Skarels  */
udp_input(mp)4325202Skarels udp_input(mp)
4425202Skarels register struct mbuf *mp;
4525202Skarels {
4625202Skarels     register struct udp *p;
4725202Skarels     register struct inpcb *inp;
4825202Skarels     register u_short i, j, ulen;
4925202Skarels 
5025202Skarels     udpstat.u_total ++;
5125202Skarels     /*
5225202Skarels      * see ip_input()
5325202Skarels      */
5425202Skarels     if ((mp->m_off > MMAXOFF) || (mp->m_len < sizeof(struct udp)))
5525202Skarels     {
5625202Skarels 	if ((mp = m_pullup(mp, sizeof(struct udp))) == NULL)
5725202Skarels 	{
5825202Skarels 	    udpstat.u_tooshort ++;
5925202Skarels 	    return;
6025202Skarels 	}
6125202Skarels     }
6225202Skarels 
6325202Skarels     p = mtod(mp, struct udp *);
6425202Skarels     ulen = ((struct ip *) p) ->ip_len; /* ip_input() set to amt IP data */
6525202Skarels     mp->m_off += sizeof p->u_x;
6625202Skarels     mp->m_len -= sizeof p->u_x;
6725202Skarels     p->u_x1 = 0;
6825202Skarels 
6925202Skarels     if (ntohs(p->u_len) != ulen)
7025202Skarels     {
7125202Skarels 	/*
7225202Skarels 	 * u_ilen overlays IP checksum, which is now zero.
7325202Skarels 	 * ulen is the actual number of bytes we got on input
7425202Skarels 	 * from IP; u_len is what UDP says we should have
7525202Skarels 	 * (sizeof(udp_specific) + datalen)
7625202Skarels 	 */
77*25216Sbloom 	log(LOG_WARNING, "UDP len %d, but got %d\n", ntohs(p->u_len), ulen);
7825202Skarels 	netlog (mp);
7925202Skarels 	return;
8025202Skarels     }
8125202Skarels     p->u_ilen = p->u_len;
8225202Skarels 
8325202Skarels     /*
8425202Skarels      * Do checksum calculation.  Assumes pseudo-header passed up from
8525202Skarels      * IP level and finished above.
8625202Skarels      * Zero checksum on send means no checksum was generated.
8725202Skarels      */
8825202Skarels     if ((i = p->u_sum) != 0)
8925202Skarels     {
9025202Skarels 	p->u_sum = 0;
9125202Skarels 	j = (u_short) in_cksum(mp, (int) (ulen + UDPCKSIZE));
9225202Skarels 	/*
9325202Skarels 	 * Remember that zero is special, and compensate for this.
9425202Skarels 	 */
9525202Skarels 	if (j == 0)
9625202Skarels 	    j = (~j);
9725202Skarels 	if (i != j)
9825202Skarels 	{
9925202Skarels 	    udpstat.u_badsum++;
10025202Skarels 	    if (! nosum)
10125202Skarels 	    {
10225202Skarels #ifdef HMPTRAPS
10325202Skarels 		/* hmp_trap(T_UDP_CKSUM, (caddr_t)0,0); */
10425202Skarels #endif
10525202Skarels 		inet_cksum_err ("udp", (struct ip *) p, (u_long) i, (u_long) j);
10625202Skarels 		netlog(mp);
10725202Skarels 		return;
10825202Skarels 	    }
10925202Skarels 	}
11025202Skarels     }
11125202Skarels 
11225202Skarels     inp = in_pcblookup(&udp, p->u_s.s_addr, (u_short)0,
11325202Skarels 			     p->u_d.s_addr, p->u_dst, TRUE);
11425202Skarels 
11525202Skarels     /* if a user is found, queue the data, otherwise drop it */
11625202Skarels 
11725202Skarels     if (inp != NULL)
11825202Skarels     {
11925202Skarels 	struct sockaddr_in udpsock;
12025202Skarels 	struct sockbuf *sorcv;
12125202Skarels 
12225202Skarels 	/*
12325202Skarels 	 * throw away entire IP and UDP leaders.
12425202Skarels 	 * user gets address separately.
12525202Skarels 	 */
12625202Skarels 	mp->m_off += sizeof (struct udp) - sizeof (p->u_x);
12725202Skarels 	mp->m_len -= sizeof (struct udp) - sizeof (p->u_x);
12825202Skarels 
12925202Skarels 	udpsock.sin_family = AF_INET;
13025202Skarels 	udpsock.sin_port = p->u_src;
13125202Skarels 	udpsock.sin_addr = p->u_s;
13225202Skarels 	udpsock.sin_zero[0] = udpsock.sin_zero[1] = 0;
13325202Skarels 
13425202Skarels 	sorcv = &inp->inp_socket->so_rcv;
13525202Skarels 
13625202Skarels 	if (! sbappendaddr(sorcv, (struct sockaddr *)&udpsock, mp,
13725202Skarels 	    (struct mbuf *) NULL))
13825202Skarels 	{
13925202Skarels 	    m_freem(mp);
14025202Skarels 	    if ((ulen - UDPSIZE + sizeof(struct sockaddr)) > sbspace(sorcv))
14125202Skarels 		udpstat.u_sonospace ++;
14225202Skarels 	    else
14325202Skarels 		udpstat.u_nobuf ++;
14425202Skarels 	}
14525202Skarels 	else
14625202Skarels 	    sorwakeup(inp->inp_socket);
14725202Skarels     }
14825202Skarels     else
14925202Skarels     {
15025202Skarels 	/*
15125202Skarels 	 * No one wants this packet.
15225202Skarels 	 */
15325202Skarels 	if (!in_broadcast(p->u_s) && !in_broadcast(p->u_d))
15425202Skarels 	    /*
15525202Skarels 	     * Don't bother everyone on the net.  Someone else may
15625202Skarels 	     * provide the service (port).
15725202Skarels 	     */
15825202Skarels 	    ic_errmsg (icmp_addr((struct ip *) p), p->u_s,
15925202Skarels 		ICMP_UNRCH, ICMP_UNRCH_PORT, 0,
16025202Skarels 		sizeof(struct ip) + ICMP_ERRLEN, (char *) p);
16125202Skarels 
16225202Skarels 	udpstat.u_drops++;
16325202Skarels 	m_freem(mp);
16425202Skarels     }
16525202Skarels }
16625202Skarels 
16725202Skarels /*
16825202Skarels  * Output a udp message.  Called from udp_usrreq().
16925202Skarels  */
17025202Skarels udp_output(inp, mp)
17125202Skarels struct inpcb *inp;
17225202Skarels register struct mbuf *mp;
17325202Skarels {
17425202Skarels     register struct udp *p;
17525202Skarels     register struct mbuf *m;
17625202Skarels     register int len;
17725202Skarels 
17825202Skarels     len = 0;
17925202Skarels     for (m = mp; m; m = m->m_next)
18025202Skarels 	len += m->m_len;
18125202Skarels 
18225202Skarels     /*
18325202Skarels      * find a place to put the IP/UDP headers.
18425202Skarels      */
18525202Skarels     m = m_get(M_WAIT, MT_HEADER);
18625202Skarels     if (m == 0)
18725202Skarels     {
18825202Skarels 	m_freem(mp);
18925202Skarels 	return (ENOBUFS);
19025202Skarels     }
19125202Skarels     m->m_next = mp;
19225202Skarels     mp = m;
19325202Skarels 
19425202Skarels     /*
19525202Skarels      * Compose header in first mbuf.  Get addresses and ports
19625202Skarels      * from ucb, add in pseudo-header fields for checksum.
19725202Skarels      * Ensure header is aligned for memory access speed...
19825202Skarels      */
19925202Skarels     mp->m_off = (MMAXOFF - sizeof(struct udp)) & ~(sizeof(long) -1);
20025202Skarels     mp->m_len = sizeof(struct udp);
20125202Skarels     p = mtod(mp, struct udp *);
20225202Skarels 
20325202Skarels     /* stuff UDP fields */
20425202Skarels     p->u_src = inp->inp_lport;
20525202Skarels     p->u_dst = inp->inp_fport;
20625202Skarels     p->u_len = htons((u_short)len+UDPSIZE);
20725202Skarels 
20825202Skarels     /* and "IP" fields */
20925202Skarels     ((struct ip *) p)->ip_tos = 0;	/* for ip_send() */
21025202Skarels     p->u_x1 = 0;
21125202Skarels     p->u_pr = IPPROTO_UDP;
21225202Skarels     p->u_ilen = p->u_len;
21325202Skarels     p->u_s = inp->inp_laddr;
21425202Skarels     p->u_d = inp->inp_faddr;
21525202Skarels 
21625202Skarels     /* Do checksum.  Include pseudo header. */
21725202Skarels     mp->m_off += sizeof p->u_x;
21825202Skarels     mp->m_len -= sizeof p->u_x;
21925202Skarels     p->u_sum = 0;
22025202Skarels     p->u_sum = in_cksum(mp, len + sizeof(struct udp) - sizeof p->u_x);
22125202Skarels     if (p->u_sum == 0)
22225202Skarels 	/* Zero is reserved for unsummed packets */
22325202Skarels 	p->u_sum = (~ p->u_sum);
22425202Skarels     mp->m_off -= sizeof p->u_x;
22525202Skarels     mp->m_len += sizeof p->u_x;
22625202Skarels 
22725202Skarels     /*
22825202Skarels      * Now send the packet via IP.
22925202Skarels      */
23025202Skarels     return(ip_send(inp, mp, len+UDPSIZE, FALSE));
23125202Skarels }
232