xref: /original-bsd/sys/deprecated/bbnnet/udp.c (revision 8af5b582)
1 #ifdef RCSIDENT
2 static char rcsident[] = "$Header: udp.c,v 1.18 85/07/31 09:44:10 walsh Exp $";
3 #endif
4 
5 
6 #include "../h/param.h"
7 #include "../h/systm.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/mbuf.h"
11 #include "../h/socket.h"
12 #include "../h/socketvar.h"
13 #include "../h/syslog.h"
14 
15 #include "../net/if.h"
16 #include "../net/route.h"
17 
18 #include "../bbnnet/in.h"
19 #include "../bbnnet/in_var.h"
20 #include "../bbnnet/net.h"
21 #include "../bbnnet/ip.h"
22 #include "../bbnnet/udp.h"
23 #include "../bbnnet/in_pcb.h"
24 #include "../bbnnet/icmp.h"
25 #ifdef HMPTRAPS
26 #include "../bbnnet/hmp_traps.h"
27 #endif
28 
29 #ifdef RCSIDENT
30 static char rcsudphdr[] = RCSUDPHDR;
31 #endif
32 
33 extern int nosum;
34 
35 struct inpcb udp;
36 struct udp_stat udpstat;
37 
38 /*
39  *  Process incoming udp messages.  Called directly from ip_input.
40  *  User sees udp header with pseudo-header which overlays ip header
41  *  (defined in udp.h).
42  */
43 udp_input(mp)
44 register struct mbuf *mp;
45 {
46     register struct udp *p;
47     register struct inpcb *inp;
48     register u_short i, j, ulen;
49 
50     udpstat.u_total ++;
51     /*
52      * see ip_input()
53      */
54     if ((mp->m_off > MMAXOFF) || (mp->m_len < sizeof(struct udp)))
55     {
56 	if ((mp = m_pullup(mp, sizeof(struct udp))) == NULL)
57 	{
58 	    udpstat.u_tooshort ++;
59 	    return;
60 	}
61     }
62 
63     p = mtod(mp, struct udp *);
64     ulen = ((struct ip *) p) ->ip_len; /* ip_input() set to amt IP data */
65     mp->m_off += sizeof p->u_x;
66     mp->m_len -= sizeof p->u_x;
67     p->u_x1 = 0;
68 
69     if (ntohs(p->u_len) != ulen)
70     {
71 	/*
72 	 * u_ilen overlays IP checksum, which is now zero.
73 	 * ulen is the actual number of bytes we got on input
74 	 * from IP; u_len is what UDP says we should have
75 	 * (sizeof(udp_specific) + datalen)
76 	 */
77 	log(LOG_WARNING, "UDP len %d, but got %d\n", ntohs(p->u_len), ulen);
78 	netlog (mp);
79 	return;
80     }
81     p->u_ilen = p->u_len;
82 
83     /*
84      * Do checksum calculation.  Assumes pseudo-header passed up from
85      * IP level and finished above.
86      * Zero checksum on send means no checksum was generated.
87      */
88     if ((i = p->u_sum) != 0)
89     {
90 	p->u_sum = 0;
91 	j = (u_short) in_cksum(mp, (int) (ulen + UDPCKSIZE));
92 	/*
93 	 * Remember that zero is special, and compensate for this.
94 	 */
95 	if (j == 0)
96 	    j = (~j);
97 	if (i != j)
98 	{
99 	    udpstat.u_badsum++;
100 	    if (! nosum)
101 	    {
102 #ifdef HMPTRAPS
103 		/* hmp_trap(T_UDP_CKSUM, (caddr_t)0,0); */
104 #endif
105 		inet_cksum_err ("udp", (struct ip *) p, (u_long) i, (u_long) j);
106 		netlog(mp);
107 		return;
108 	    }
109 	}
110     }
111 
112     inp = in_pcblookup(&udp, p->u_s.s_addr, (u_short)0,
113 			     p->u_d.s_addr, p->u_dst, TRUE);
114 
115     /* if a user is found, queue the data, otherwise drop it */
116 
117     if (inp != NULL)
118     {
119 	struct sockaddr_in udpsock;
120 	struct sockbuf *sorcv;
121 
122 	/*
123 	 * throw away entire IP and UDP leaders.
124 	 * user gets address separately.
125 	 */
126 	mp->m_off += sizeof (struct udp) - sizeof (p->u_x);
127 	mp->m_len -= sizeof (struct udp) - sizeof (p->u_x);
128 
129 	udpsock.sin_family = AF_INET;
130 	udpsock.sin_port = p->u_src;
131 	udpsock.sin_addr = p->u_s;
132 	udpsock.sin_zero[0] = udpsock.sin_zero[1] = 0;
133 
134 	sorcv = &inp->inp_socket->so_rcv;
135 
136 	if (! sbappendaddr(sorcv, (struct sockaddr *)&udpsock, mp,
137 	    (struct mbuf *) NULL))
138 	{
139 	    m_freem(mp);
140 	    if ((ulen - UDPSIZE + sizeof(struct sockaddr)) > sbspace(sorcv))
141 		udpstat.u_sonospace ++;
142 	    else
143 		udpstat.u_nobuf ++;
144 	}
145 	else
146 	    sorwakeup(inp->inp_socket);
147     }
148     else
149     {
150 	/*
151 	 * No one wants this packet.
152 	 */
153 	if (!in_broadcast(p->u_s) && !in_broadcast(p->u_d))
154 	    /*
155 	     * Don't bother everyone on the net.  Someone else may
156 	     * provide the service (port).
157 	     */
158 	    ic_errmsg (icmp_addr((struct ip *) p), p->u_s,
159 		ICMP_UNRCH, ICMP_UNRCH_PORT, 0,
160 		sizeof(struct ip) + ICMP_ERRLEN, (char *) p);
161 
162 	udpstat.u_drops++;
163 	m_freem(mp);
164     }
165 }
166 
167 /*
168  * Output a udp message.  Called from udp_usrreq().
169  */
170 udp_output(inp, mp)
171 struct inpcb *inp;
172 register struct mbuf *mp;
173 {
174     register struct udp *p;
175     register struct mbuf *m;
176     register int len;
177 
178     len = 0;
179     for (m = mp; m; m = m->m_next)
180 	len += m->m_len;
181 
182     /*
183      * find a place to put the IP/UDP headers.
184      */
185     m = m_get(M_WAIT, MT_HEADER);
186     if (m == 0)
187     {
188 	m_freem(mp);
189 	return (ENOBUFS);
190     }
191     m->m_next = mp;
192     mp = m;
193 
194     /*
195      * Compose header in first mbuf.  Get addresses and ports
196      * from ucb, add in pseudo-header fields for checksum.
197      * Ensure header is aligned for memory access speed...
198      */
199     mp->m_off = (MMAXOFF - sizeof(struct udp)) & ~(sizeof(long) -1);
200     mp->m_len = sizeof(struct udp);
201     p = mtod(mp, struct udp *);
202 
203     /* stuff UDP fields */
204     p->u_src = inp->inp_lport;
205     p->u_dst = inp->inp_fport;
206     p->u_len = htons((u_short)len+UDPSIZE);
207 
208     /* and "IP" fields */
209     ((struct ip *) p)->ip_tos = 0;	/* for ip_send() */
210     p->u_x1 = 0;
211     p->u_pr = IPPROTO_UDP;
212     p->u_ilen = p->u_len;
213     p->u_s = inp->inp_laddr;
214     p->u_d = inp->inp_faddr;
215 
216     /* Do checksum.  Include pseudo header. */
217     mp->m_off += sizeof p->u_x;
218     mp->m_len -= sizeof p->u_x;
219     p->u_sum = 0;
220     p->u_sum = in_cksum(mp, len + sizeof(struct udp) - sizeof p->u_x);
221     if (p->u_sum == 0)
222 	/* Zero is reserved for unsummed packets */
223 	p->u_sum = (~ p->u_sum);
224     mp->m_off -= sizeof p->u_x;
225     mp->m_len += sizeof p->u_x;
226 
227     /*
228      * Now send the packet via IP.
229      */
230     return(ip_send(inp, mp, len+UDPSIZE, FALSE));
231 }
232