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