fixes for range locking
[unix-history] / usr / src / sys / deprecated / bbnnet / udp.c
CommitLineData
17efd7fe
MK
1#ifdef RCSIDENT
2static 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
30static char rcsudphdr[] = RCSUDPHDR;
31#endif
32
33extern int nosum;
34
35struct inpcb udp;
36struct 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 */
43udp_input(mp)
44register 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 */
1969a567 77 log(LOG_WARNING, "UDP len %d, but got %d\n", ntohs(p->u_len), ulen);
17efd7fe
MK
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 */
170udp_output(inp, mp)
171struct inpcb *inp;
172register 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}