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"); 190 log(LOG_INFO, "%d + %d != %d\n", hdrlen(pkt), pkt->rh_dlen, 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 405