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