Commit | Line | Data |
---|---|---|
17efd7fe MK |
1 | /* |
2 | $Log: rdp_input.c,v $ | |
3 | * Revision 2.10 85/06/18 14:37:38 walsh | |
4 | * check for version mismatch. | |
5 | * | |
6 | * Revision 2.9 85/04/08 14:35:11 root | |
7 | * *** empty log message *** | |
8 | * | |
9 | * Revision 2.8 85/02/26 08:26:48 walsh | |
10 | * First pass at using IP source routing information to establish connections | |
11 | * (possibly with hosts not known by the Internet gateways.) The hooks with | |
12 | * TCP could be better done - particularly dealing with IP addresses in the | |
13 | * header for checksums and tcpdb lookups. | |
14 | * | |
15 | * Revision 2.7 84/11/15 09:55:52 walsh | |
16 | * redid how we deal with compiler padding in the RDP header structure. | |
17 | * | |
18 | * Revision 2.6 84/11/08 16:11:17 walsh | |
19 | * Added code to gather statistics on RDP traffic. This makes the RDPCB | |
20 | * too big unles you make mbufs 512 bytes large. RDP_CS should be turned off | |
21 | * unless you do. | |
22 | * | |
23 | * Revision 2.5 84/11/06 14:30:09 walsh | |
24 | * intorduced RDP_HLSHIFT | |
25 | * | |
26 | * Revision 2.4 84/11/05 16:33:07 walsh | |
27 | * fix coding error. | |
28 | * | |
29 | * Revision 2.3 84/11/05 10:51:53 walsh | |
30 | * flush debugging log if new state is RDP_sCLOSED so that packet printer/ | |
31 | * system analyst sees final transitions. | |
32 | * | |
33 | * Revision 2.2 84/11/02 15:28:19 walsh | |
34 | * Allow for RDP header fields not on natural boundries. (Protocol | |
35 | * specifiers say will be part of next version in 6-12 months). | |
36 | * Until then, there goes the speed... Yucho modifications. | |
37 | * | |
38 | * Revision 2.1 84/11/02 10:12:58 walsh | |
39 | * Fixed to include RCS comments in checked out source. | |
40 | * | |
41 | * | |
42 | * description: | |
43 | * Packet input processing for Reliable Datagram Protocol. | |
44 | * | |
45 | * revision 1.6 | |
46 | * date: 84/07/19 10:21:22; author: walsh; state: Exp; lines added/del: 2/1 | |
47 | * Organized macros and classified their definitions in rdp_macros.h. | |
48 | * | |
49 | * revision 1.5 | |
50 | * date: 84/07/10 09:59:38; author: walsh; state: Exp; lines added/del: 10/10 | |
51 | * declared some register variables. | |
52 | * | |
53 | * revision 1.4 | |
54 | * date: 84/07/06 14:43:19; author: wjacobso; state: Exp; lines added/del: 2/2 | |
55 | * *** empty log message *** | |
56 | * | |
57 | * revision 1.3 | |
58 | * date: 84/07/06 13:50:26; author: wjacobso; state: Exp; lines added/del: 6/3 | |
59 | * use RDP_ACTION macro instead of rdp_action | |
60 | * | |
61 | * revision 1.2 | |
62 | * date: 84/07/06 09:49:20; author: root; state: Exp; lines added/del: 27/45 | |
63 | * This version seems to run bug-free. | |
64 | * | |
65 | * revision 1.1 | |
66 | * date: 84/06/26 14:17:19; author: walsh; state: Exp; | |
67 | * Initial revision | |
68 | */ | |
69 | ||
70 | ||
71 | #ifdef RDP | |
72 | #ifdef RCSIDENT | |
73 | static char rcsident[] = "$Header: rdp_input.c,v 2.10 85/06/18 14:37:38 walsh Exp $"; | |
74 | #endif | |
75 | ||
76 | #include "../h/param.h" | |
77 | #include "../h/dir.h" | |
78 | #include "../h/user.h" | |
79 | #include "../h/kernel.h" | |
80 | #include "../h/inode.h" | |
81 | #include "../h/mbuf.h" | |
82 | #include "../h/socket.h" | |
83 | #include "../h/socketvar.h" | |
84 | #include "../h/syslog.h" | |
85 | ||
86 | #include "../net/if.h" | |
87 | #include "../net/route.h" | |
88 | ||
89 | #include "../bbnnet/in.h" | |
90 | #include "../bbnnet/in_var.h" | |
91 | #include "../bbnnet/net.h" | |
92 | #include "../bbnnet/in_pcb.h" | |
93 | #include "../bbnnet/ip.h" | |
94 | #include "../bbnnet/nopcb.h" | |
95 | #include "../bbnnet/rdp.h" | |
96 | #include "../bbnnet/rdp_macros.h" | |
97 | #ifdef HMP | |
98 | #include "../bbnnet/hmp_traps.h" | |
99 | #endif | |
100 | ||
101 | extern int nosum; | |
102 | ||
103 | /* | |
104 | * this is called from ip_input() upon reception of an RDP packet. | |
105 | */ | |
106 | rdp_input(mp) | |
107 | register struct mbuf *mp; | |
108 | { | |
109 | register RDPHDR *pkt; | |
110 | register struct ip *ip; | |
111 | rdpchecksum pktcksum; | |
112 | rdpchecksum cksum; | |
113 | register int hlen; | |
114 | register struct inpcb *inp; | |
115 | ||
116 | rdpstat.r_total++; | |
117 | ||
118 | /* | |
119 | * see ip_input(). Get access to constant part of RDP header. | |
120 | */ | |
121 | #define SZ (RDPHDRSZ + sizeof(struct ip)) | |
122 | if ((mp->m_off > MMAXOFF) || (mp->m_len < SZ)) | |
123 | { | |
124 | if ((mp = m_pullup(mp, SZ)) == NULL) | |
125 | { | |
126 | rdpstat.r_tooshort ++; | |
127 | return; | |
128 | } | |
129 | } | |
130 | #undef SZ | |
131 | ||
132 | ip = mtod(mp, struct ip *); | |
133 | pkt = (RDPHDR *) (ip + 1); | |
134 | ||
135 | /* make sure header, incl. option region, does not overflow mbuf */ | |
136 | ||
137 | hlen = hdrlen(pkt) + sizeof(struct ip); | |
138 | if (hlen > mp->m_len) | |
139 | { | |
140 | if ((mp = m_pullup(mp, hlen)) == NULL) | |
141 | { | |
142 | ip_log(ip, "rdp header overflow"); | |
143 | #ifdef HMPTRAPS | |
144 | /* hmp_trap(T_TCP_OVFLO, (caddr_t)0,0); */ | |
145 | #else | |
146 | /* netlog(mp); */ | |
147 | #endif | |
148 | return; | |
149 | } | |
150 | ip = mtod(mp, struct ip *); | |
151 | pkt = (RDPHDR *) (ip + 1); | |
152 | } | |
153 | ||
154 | if (pkt->rh_ver != RDP_VERSION) | |
155 | { | |
156 | ip_log (ip, "rdp version mismatch"); | |
157 | netlog (mp); | |
158 | return; | |
159 | } | |
160 | ||
161 | /* | |
162 | * do checksum calculation, drop packet if bad | |
163 | * Checksum must be done on header in net form due to byte ordering | |
164 | * and rotations. | |
165 | */ | |
166 | ||
167 | pktcksum = RDP_CKSUM(pkt); | |
168 | RDP_CKSUM(pkt) = 0; | |
169 | cksum = rdp_cksum(mp); | |
170 | if (cksum != pktcksum) | |
171 | { | |
172 | rdpstat.r_badsum++; | |
173 | if (! nosum) | |
174 | { | |
175 | inet_cksum_err ("rdp", ip, (u_long) pktcksum, (u_long) cksum); | |
176 | netlog(mp); | |
177 | return; | |
178 | } | |
179 | } | |
180 | ||
181 | /* byte swap header */ | |
182 | ||
183 | pkt->rh_dlen = ntohs(pkt->rh_dlen); | |
184 | RDP_SEQNO(pkt) = ntohl(RDP_SEQNO(pkt)); | |
185 | RDP_ACKNO(pkt) = ntohl(RDP_ACKNO(pkt)); | |
186 | ||
187 | if (ip->ip_len != hdrlen(pkt) + pkt->rh_dlen) | |
188 | { | |
189 | ip_log(ip, "rdp length error"); | |
8902c2d0 | 190 | log(LOG_INFO, "%d + %d != %d\n", hdrlen(pkt), pkt->rh_dlen, |
17efd7fe MK |
191 | ip->ip_len); |
192 | netlog(mp); | |
193 | return; | |
194 | } | |
195 | ||
196 | inp = in_pcblookup(&rdp, ip->ip_src.s_addr, (u_short)pkt->rh_sport, | |
197 | ip->ip_dst.s_addr, (u_short)pkt->rh_dport, TRUE); | |
198 | if (inp == NULL) | |
199 | { | |
200 | /* nobody wants it */ | |
201 | rdpstat.r_drops ++; | |
202 | rdp_uncon_rst (pkt); | |
203 | } | |
204 | else | |
205 | { | |
206 | register rdpstate newstate; | |
207 | register RDPCB *rdpcb; | |
208 | ||
209 | rdpcb = (RDPCB *)inp->inp_ppcb; | |
210 | ||
211 | #ifdef RDP_CS | |
212 | rdpcb->r_rcvd.r_total ++; | |
213 | if (pkt->rh_flags & (RDP_fNULL|RDP_fRST|RDP_fSYN)) | |
214 | { | |
215 | if (pkt->rh_flags & RDP_fNULL) | |
216 | rdpcb->r_rcvd.r_nullpkts ++; | |
217 | if (pkt->rh_flags & RDP_fRST) | |
218 | rdpcb->r_rcvd.r_rstpkts ++; | |
219 | if (pkt->rh_flags & RDP_fSYN) | |
220 | rdpcb->r_rcvd.r_synpkts ++; | |
221 | } | |
222 | #endif | |
223 | /* found a protocol control block for the message */ | |
224 | RDP_ACTION(RDP_iNETR, rdpcb, ((int) pkt), newstate); | |
225 | } | |
226 | } | |
227 | ||
228 | ||
229 | /* | |
230 | * Call a subroutine specifically tailored to deal with this state | |
231 | * transition. | |
232 | */ | |
233 | rdpaction (input, rdpcb, arg) | |
234 | register RDPCB *rdpcb; | |
235 | { | |
236 | register rdpstate newstate; | |
237 | ||
238 | RDP_ACTION (input, rdpcb, arg, newstate) | |
239 | } | |
240 | ||
241 | rdp_uncon_rst (pkt) | |
242 | register RDPHDR *pkt; | |
243 | { | |
244 | register struct ip *ip; | |
245 | register struct mbuf *mp; | |
246 | struct in_addr tempinaddr; | |
247 | rdpportnum tempport; | |
248 | long his_seqno; | |
249 | int error; | |
250 | ||
251 | mp = dtom(pkt); | |
252 | ||
253 | /* make sure we don't send a RST in response to an RST */ | |
254 | ||
255 | if (pkt->rh_flags & RDP_fRST) | |
256 | { | |
257 | m_freem(mp); | |
258 | return; | |
259 | } | |
260 | ip = (struct ip *) (((caddr_t) pkt) - sizeof(struct ip)); | |
261 | ||
262 | /* free everything but the header */ | |
263 | ||
264 | m_freem(mp->m_next); | |
265 | mp->m_next = NULL; | |
266 | mp->m_len = sizeof(struct ip) + RDPHDRSZ; | |
267 | ||
268 | /* direct the packet back to the originator */ | |
269 | ||
270 | tempinaddr = ip->ip_dst; | |
271 | ip->ip_dst = ip->ip_src; | |
272 | ip->ip_src = tempinaddr; | |
273 | ||
274 | tempport = pkt->rh_sport; | |
275 | pkt->rh_sport = pkt->rh_dport; | |
276 | pkt->rh_dport = tempport; | |
277 | ||
278 | /* | |
279 | * and initialize (seqno, ackno, flags) so that it's "in window" | |
280 | * and resets him independent of his state (is acceptable to all | |
281 | * net reception subroutines.) | |
282 | */ | |
283 | his_seqno = RDP_SEQNO(pkt); | |
284 | RDP_SEQNO(pkt) = htonl(RDP_ACKNO(pkt) + 1); | |
285 | RDP_ACKNO(pkt) = htonl(his_seqno); | |
286 | if (pkt->rh_flags & RDP_fSYN) | |
287 | pkt->rh_flags = RDP_fRST|RDP_fACK; | |
288 | else | |
289 | pkt->rh_flags = RDP_fRST; | |
290 | ||
291 | /* and send it */ | |
292 | ||
293 | pkt->rh_hdrlen = RDPHDRSZ >> RDP_HLSHIFT; | |
294 | pkt->rh_dlen = 0; | |
295 | RDP_CKSUM(pkt) = 0; | |
296 | ||
297 | RDP_CKSUM(pkt) = rdp_cksum(mp); | |
298 | ||
299 | NOPCB_IPSEND (mp, RDPHDRSZ, FALSE, error); | |
300 | #ifdef lint | |
301 | error = error; | |
302 | #endif | |
303 | } | |
304 | ||
305 | struct mbuf *rdpdebuf; | |
306 | #ifdef RDPDEBUG | |
307 | int rdprint; | |
308 | #endif | |
309 | ||
310 | /* | |
311 | * Write a record in the rdp debugging log | |
312 | */ | |
313 | rdp_debug(rdpcb, arg, input, newstate) | |
314 | register RDPCB *rdpcb; | |
315 | rdpstate newstate; | |
316 | { | |
317 | register struct r_debug *dp; | |
318 | register struct mbuf *m; | |
319 | ||
320 | #ifdef RDPDEBUG | |
321 | if (rdprint) | |
322 | { | |
323 | /* | |
324 | * Print debugging info directly on the console (use this for | |
325 | * intial testing only). | |
326 | */ | |
327 | printf("RDP(0x%x) %s X %s", rdpcb, rdpstates[rdpcb->r_state], | |
328 | (input < 0 ? "send pkt" : rdpinputs[input]) ); | |
329 | ||
330 | if (input == RDP_iTIMER) | |
331 | printf("(%s)", rdptimers[arg]); | |
332 | ||
333 | printf(" --> %s\n", | |
334 | rdpstates[newstate==RDP_sSAME ? rdpcb->r_state : newstate]; | |
335 | } | |
336 | #endif | |
337 | ||
338 | /* | |
339 | * Get an mbuf to write the debugging record into. If we don't already | |
340 | * have one, allocate a new one. | |
341 | */ | |
342 | if ((m = rdpdebuf) == NULL) | |
343 | { | |
344 | register struct mbuf *c; | |
345 | ||
346 | if ((rdpdebuf = m = m_get(M_DONTWAIT, MT_DATA)) == NULL) | |
347 | return; | |
348 | /* | |
349 | * If possible, use a cluster so that we need to wake up the | |
350 | * raw listener less often and reduce likelihood he misses | |
351 | * some information. | |
352 | */ | |
353 | MCLGET(c, 1); | |
354 | if (c) | |
355 | { | |
356 | m->m_off = ((int) c) - ((int) m); | |
357 | m->m_act = (struct mbuf *) RCDBLEN; | |
358 | } | |
359 | else | |
360 | m->m_act = (struct mbuf *) RDBLEN; | |
361 | m->m_len = 0; | |
362 | } | |
363 | ||
364 | dp = (R_DEBUG *) (mtod(m, char *) + m->m_len); | |
365 | /* | |
366 | * Set up the debugging record. | |
367 | */ | |
368 | dp->rd_iptime = iptime(); | |
369 | dp->rd_input = input; | |
370 | dp->rd_newstate = newstate; | |
371 | dp->rd_rdpcb = (*rdpcb); /* structure copy */ | |
372 | ||
373 | /* | |
374 | * input == RDP_iNETR incoming packet | |
375 | * == -1 monitor outgoing packet. Not a true | |
376 | * transition CAUSING event, but useful. | |
377 | */ | |
378 | if ((input == RDP_iNETR) || (input < 0)) | |
379 | { | |
380 | register struct ip *ip; | |
381 | register RDPHDR *pkt; | |
382 | ||
383 | ip = (struct ip *) arg; | |
384 | pkt = (RDPHDR *) (ip + 1); | |
385 | dp->rd_iphdr = (*ip); /* structure copy */ | |
386 | dp->rd_rdphdr = (*pkt); /* structure copy */ | |
387 | } | |
388 | else if (input == RDP_iTIMER) | |
389 | dp->rd_timer = arg; | |
390 | ||
391 | /* | |
392 | * If the mbuf is full, dispatch it to a raw listener. | |
393 | * Also for transition to closed state so oberver sees all and | |
394 | * can debug stuff more easily. | |
395 | */ | |
396 | m->m_len += sizeof(struct r_debug); | |
397 | if ((m->m_len >= ((int) m->m_act)) || (newstate == RDP_sCLOSED)) | |
398 | { | |
399 | m->m_act = 0; | |
400 | rdpdebuglog(m); | |
401 | rdpdebuf = NULL; | |
402 | } | |
403 | } | |
404 | #endif |