1 /* udp_usrreq.c 6.1 83/07/29 */ 2 3 #include "../h/param.h" 4 #include "../h/dir.h" 5 #include "../h/user.h" 6 #include "../h/mbuf.h" 7 #include "../h/protosw.h" 8 #include "../h/socket.h" 9 #include "../h/socketvar.h" 10 #include "../h/errno.h" 11 12 #include "../net/if.h" 13 #include "../net/route.h" 14 15 #include "../netinet/in.h" 16 #include "../netinet/in_pcb.h" 17 #include "../netinet/in_systm.h" 18 #include "../netinet/ip.h" 19 #include "../netinet/ip_var.h" 20 #include "../netinet/ip_icmp.h" 21 #include "../netinet/udp.h" 22 #include "../netinet/udp_var.h" 23 24 /* 25 * UDP protocol implementation. 26 * Per RFC 768, August, 1980. 27 */ 28 udp_init() 29 { 30 31 udb.inp_next = udb.inp_prev = &udb; 32 } 33 34 int udpcksum; 35 struct sockaddr_in udp_in = { AF_INET }; 36 37 udp_input(m0) 38 struct mbuf *m0; 39 { 40 register struct udpiphdr *ui; 41 register struct inpcb *inp; 42 register struct mbuf *m; 43 int len; 44 45 /* 46 * Get IP and UDP header together in first mbuf. 47 */ 48 m = m0; 49 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 50 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 51 udpstat.udps_hdrops++; 52 return; 53 } 54 ui = mtod(m, struct udpiphdr *); 55 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 56 ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 57 58 /* 59 * Make mbuf data length reflect UDP length. 60 * If not enough data to reflect UDP length, drop. 61 */ 62 len = ntohs((u_short)ui->ui_ulen); 63 if (((struct ip *)ui)->ip_len != len) { 64 if (len > ((struct ip *)ui)->ip_len) { 65 udpstat.udps_badlen++; 66 goto bad; 67 } 68 m_adj(m, ((struct ip *)ui)->ip_len - len); 69 /* (struct ip *)ui->ip_len = len; */ 70 } 71 72 /* 73 * Checksum extended UDP header and data. 74 */ 75 if (udpcksum) { 76 ui->ui_next = ui->ui_prev = 0; 77 ui->ui_x1 = 0; 78 ui->ui_len = htons((u_short)len); 79 if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 80 udpstat.udps_badsum++; 81 m_freem(m); 82 return; 83 } 84 } 85 86 /* 87 * Locate pcb for datagram. 88 */ 89 inp = in_pcblookup(&udb, 90 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 91 INPLOOKUP_WILDCARD); 92 if (inp == 0) { 93 /* don't send ICMP response for broadcast packet */ 94 if (in_lnaof(ui->ui_dst) == INADDR_ANY) 95 goto bad; 96 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT); 97 return; 98 } 99 100 /* 101 * Construct sockaddr format source address. 102 * Stuff source address and datagram in user buffer. 103 */ 104 udp_in.sin_port = ui->ui_sport; 105 udp_in.sin_addr = ui->ui_src; 106 m->m_len -= sizeof (struct udpiphdr); 107 m->m_off += sizeof (struct udpiphdr); 108 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 109 m, (struct mbuf *)0) == 0) 110 goto bad; 111 sorwakeup(inp->inp_socket); 112 return; 113 bad: 114 m_freem(m); 115 } 116 117 udp_abort(inp) 118 struct inpcb *inp; 119 { 120 struct socket *so = inp->inp_socket; 121 122 in_pcbdisconnect(inp); 123 soisdisconnected(so); 124 } 125 126 udp_ctlinput(cmd, arg) 127 int cmd; 128 caddr_t arg; 129 { 130 struct in_addr *sin; 131 extern u_char inetctlerrmap[]; 132 133 if (cmd < 0 || cmd > PRC_NCMDS) 134 return; 135 switch (cmd) { 136 137 case PRC_ROUTEDEAD: 138 break; 139 140 case PRC_QUENCH: 141 break; 142 143 /* these are handled by ip */ 144 case PRC_IFDOWN: 145 case PRC_HOSTDEAD: 146 case PRC_HOSTUNREACH: 147 break; 148 149 default: 150 sin = &((struct icmp *)arg)->icmp_ip.ip_dst; 151 in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort); 152 } 153 } 154 155 udp_output(inp, m0) 156 struct inpcb *inp; 157 struct mbuf *m0; 158 { 159 register struct mbuf *m; 160 register struct udpiphdr *ui; 161 register struct socket *so; 162 register int len = 0; 163 int flags; 164 165 /* 166 * Calculate data length and get a mbuf 167 * for UDP and IP headers. 168 */ 169 for (m = m0; m; m = m->m_next) 170 len += m->m_len; 171 m = m_get(M_DONTWAIT, MT_HEADER); 172 if (m == 0) { 173 m_freem(m0); 174 return (ENOBUFS); 175 } 176 177 /* 178 * Fill in mbuf with extended UDP header 179 * and addresses and length put into network format. 180 */ 181 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 182 m->m_len = sizeof (struct udpiphdr); 183 m->m_next = m0; 184 ui = mtod(m, struct udpiphdr *); 185 ui->ui_next = ui->ui_prev = 0; 186 ui->ui_x1 = 0; 187 ui->ui_pr = IPPROTO_UDP; 188 ui->ui_len = len + sizeof (struct udphdr); 189 ui->ui_src = inp->inp_laddr; 190 ui->ui_dst = inp->inp_faddr; 191 ui->ui_sport = inp->inp_lport; 192 ui->ui_dport = inp->inp_fport; 193 ui->ui_ulen = htons((u_short)ui->ui_len); 194 195 /* 196 * Stuff checksum and output datagram. 197 */ 198 ui->ui_sum = 0; 199 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); 200 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 201 ((struct ip *)ui)->ip_ttl = MAXTTL; 202 so = inp->inp_socket; 203 flags = (so->so_options & SO_DONTROUTE) | (so->so_state & SS_PRIV); 204 return (ip_output(m, (struct mbuf *)0, (struct route *)0, flags)); 205 } 206 207 /*ARGSUSED*/ 208 udp_usrreq(so, req, m, nam, rights) 209 struct socket *so; 210 int req; 211 struct mbuf *m, *nam, *rights; 212 { 213 struct inpcb *inp = sotoinpcb(so); 214 int error = 0; 215 216 if (rights && rights->m_len) { 217 error = EINVAL; 218 goto release; 219 } 220 if (inp == NULL && req != PRU_ATTACH) { 221 error = EINVAL; 222 goto release; 223 } 224 switch (req) { 225 226 case PRU_ATTACH: 227 if (inp != NULL) { 228 error = EINVAL; 229 break; 230 } 231 error = in_pcballoc(so, &udb); 232 if (error) 233 break; 234 error = soreserve(so, 2048, 2048); 235 if (error) 236 break; 237 break; 238 239 case PRU_DETACH: 240 if (inp == NULL) { 241 error = ENOTCONN; 242 break; 243 } 244 in_pcbdetach(inp); 245 break; 246 247 case PRU_BIND: 248 error = in_pcbbind(inp, nam); 249 break; 250 251 case PRU_LISTEN: 252 error = EOPNOTSUPP; 253 break; 254 255 case PRU_CONNECT: 256 if (inp->inp_faddr.s_addr != INADDR_ANY) { 257 error = EISCONN; 258 break; 259 } 260 error = in_pcbconnect(inp, nam); 261 if (error == 0) 262 soisconnected(so); 263 break; 264 265 case PRU_CONNECT2: 266 error = EOPNOTSUPP; 267 break; 268 269 case PRU_ACCEPT: 270 error = EOPNOTSUPP; 271 break; 272 273 case PRU_DISCONNECT: 274 if (inp->inp_faddr.s_addr == INADDR_ANY) { 275 error = ENOTCONN; 276 break; 277 } 278 in_pcbdisconnect(inp); 279 soisdisconnected(so); 280 break; 281 282 case PRU_SHUTDOWN: 283 socantsendmore(so); 284 break; 285 286 case PRU_SEND: { 287 struct in_addr laddr; 288 289 if (nam) { 290 laddr = inp->inp_laddr; 291 if (inp->inp_faddr.s_addr != INADDR_ANY) { 292 error = EISCONN; 293 break; 294 } 295 error = in_pcbconnect(inp, nam); 296 if (error) 297 break; 298 } else { 299 if (inp->inp_faddr.s_addr == INADDR_ANY) { 300 error = ENOTCONN; 301 break; 302 } 303 } 304 error = udp_output(inp, m); 305 m = NULL; 306 if (nam) { 307 in_pcbdisconnect(inp); 308 inp->inp_laddr = laddr; 309 } 310 } 311 break; 312 313 case PRU_ABORT: 314 in_pcbdetach(inp); 315 sofree(so); 316 soisdisconnected(so); 317 break; 318 319 case PRU_SOCKADDR: 320 in_setsockaddr(inp, nam); 321 break; 322 323 case PRU_PEERADDR: 324 in_setpeeraddr(inp, nam); 325 break; 326 327 case PRU_CONTROL: 328 m = NULL; 329 error = EOPNOTSUPP; 330 break; 331 332 case PRU_SENSE: 333 m = NULL; 334 /* fall thru... */ 335 336 case PRU_RCVD: 337 case PRU_RCVOOB: 338 case PRU_SENDOOB: 339 case PRU_FASTTIMO: 340 case PRU_SLOWTIMO: 341 case PRU_PROTORCV: 342 case PRU_PROTOSEND: 343 error = EOPNOTSUPP; 344 break; 345 346 default: 347 panic("udp_usrreq"); 348 } 349 release: 350 if (m != NULL) 351 m_freem(m); 352 return (error); 353 } 354