1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)udp_usrreq.c 7.2 (Berkeley) 06/04/87 7 */ 8 9 #include "param.h" 10 #include "dir.h" 11 #include "user.h" 12 #include "mbuf.h" 13 #include "protosw.h" 14 #include "socket.h" 15 #include "socketvar.h" 16 #include "errno.h" 17 #include "stat.h" 18 19 #include "../net/if.h" 20 #include "../net/route.h" 21 22 #include "in.h" 23 #include "in_pcb.h" 24 #include "in_systm.h" 25 #include "ip.h" 26 #include "ip_var.h" 27 #include "ip_icmp.h" 28 #include "udp.h" 29 #include "udp_var.h" 30 31 /* 32 * UDP protocol implementation. 33 * Per RFC 768, August, 1980. 34 */ 35 udp_init() 36 { 37 38 udb.inp_next = udb.inp_prev = &udb; 39 } 40 41 #ifndef COMPAT_42 42 int udpcksum = 1; 43 #else 44 int udpcksum = 0; /* XXX */ 45 #endif 46 int udp_ttl = UDP_TTL; 47 48 struct sockaddr_in udp_in = { AF_INET }; 49 50 udp_input(m0, ifp) 51 struct mbuf *m0; 52 struct ifnet *ifp; 53 { 54 register struct udpiphdr *ui; 55 register struct inpcb *inp; 56 register struct mbuf *m; 57 int len; 58 struct ip ip; 59 60 /* 61 * Get IP and UDP header together in first mbuf. 62 */ 63 m = m0; 64 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && 65 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { 66 udpstat.udps_hdrops++; 67 return; 68 } 69 ui = mtod(m, struct udpiphdr *); 70 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) 71 ip_stripoptions((struct ip *)ui, (struct mbuf *)0); 72 73 /* 74 * Make mbuf data length reflect UDP length. 75 * If not enough data to reflect UDP length, drop. 76 */ 77 len = ntohs((u_short)ui->ui_ulen); 78 if (((struct ip *)ui)->ip_len != len) { 79 if (len > ((struct ip *)ui)->ip_len) { 80 udpstat.udps_badlen++; 81 goto bad; 82 } 83 m_adj(m, len - ((struct ip *)ui)->ip_len); 84 /* ((struct ip *)ui)->ip_len = len; */ 85 } 86 /* 87 * Save a copy of the IP header in case we want restore it for ICMP. 88 */ 89 ip = *(struct ip*)ui; 90 91 /* 92 * Checksum extended UDP header and data. 93 */ 94 if (udpcksum && ui->ui_sum) { 95 ui->ui_next = ui->ui_prev = 0; 96 ui->ui_x1 = 0; 97 ui->ui_len = ui->ui_ulen; 98 if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { 99 udpstat.udps_badsum++; 100 m_freem(m); 101 return; 102 } 103 } 104 105 /* 106 * Locate pcb for datagram. 107 */ 108 inp = in_pcblookup(&udb, 109 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, 110 INPLOOKUP_WILDCARD); 111 if (inp == 0) { 112 /* don't send ICMP response for broadcast packet */ 113 if (in_broadcast(ui->ui_dst)) 114 goto bad; 115 *(struct ip *)ui = ip; 116 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, 117 ifp); 118 return; 119 } 120 121 /* 122 * Construct sockaddr format source address. 123 * Stuff source address and datagram in user buffer. 124 */ 125 udp_in.sin_port = ui->ui_sport; 126 udp_in.sin_addr = ui->ui_src; 127 m->m_len -= sizeof (struct udpiphdr); 128 m->m_off += sizeof (struct udpiphdr); 129 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 130 m, (struct mbuf *)0) == 0) 131 goto bad; 132 sorwakeup(inp->inp_socket); 133 return; 134 bad: 135 m_freem(m); 136 } 137 138 /* 139 * Notify a udp user of an asynchronous error; 140 * just wake up so that he can collect error status. 141 */ 142 udp_notify(inp) 143 register struct inpcb *inp; 144 { 145 146 sorwakeup(inp->inp_socket); 147 sowwakeup(inp->inp_socket); 148 } 149 150 udp_ctlinput(cmd, sa) 151 int cmd; 152 struct sockaddr *sa; 153 { 154 extern u_char inetctlerrmap[]; 155 struct sockaddr_in *sin; 156 int in_rtchange(); 157 158 if ((unsigned)cmd > PRC_NCMDS) 159 return; 160 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 161 return; 162 sin = (struct sockaddr_in *)sa; 163 if (sin->sin_addr.s_addr == INADDR_ANY) 164 return; 165 166 switch (cmd) { 167 168 case PRC_QUENCH: 169 break; 170 171 case PRC_ROUTEDEAD: 172 case PRC_REDIRECT_NET: 173 case PRC_REDIRECT_HOST: 174 case PRC_REDIRECT_TOSNET: 175 case PRC_REDIRECT_TOSHOST: 176 in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); 177 break; 178 179 default: 180 if (inetctlerrmap[cmd] == 0) 181 return; /* XXX */ 182 in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], 183 udp_notify); 184 } 185 } 186 187 udp_output(inp, m0) 188 register struct inpcb *inp; 189 struct mbuf *m0; 190 { 191 register struct mbuf *m; 192 register struct udpiphdr *ui; 193 register int len = 0; 194 195 /* 196 * Calculate data length and get a mbuf 197 * for UDP and IP headers. 198 */ 199 for (m = m0; m; m = m->m_next) 200 len += m->m_len; 201 MGET(m, M_DONTWAIT, MT_HEADER); 202 if (m == 0) { 203 m_freem(m0); 204 return (ENOBUFS); 205 } 206 207 /* 208 * Fill in mbuf with extended UDP header 209 * and addresses and length put into network format. 210 */ 211 m->m_off = MMAXOFF - sizeof (struct udpiphdr); 212 m->m_len = sizeof (struct udpiphdr); 213 m->m_next = m0; 214 ui = mtod(m, struct udpiphdr *); 215 ui->ui_next = ui->ui_prev = 0; 216 ui->ui_x1 = 0; 217 ui->ui_pr = IPPROTO_UDP; 218 ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 219 ui->ui_src = inp->inp_laddr; 220 ui->ui_dst = inp->inp_faddr; 221 ui->ui_sport = inp->inp_lport; 222 ui->ui_dport = inp->inp_fport; 223 ui->ui_ulen = ui->ui_len; 224 225 /* 226 * Stuff checksum and output datagram. 227 */ 228 ui->ui_sum = 0; 229 if (udpcksum) { 230 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 231 ui->ui_sum = -1; 232 } 233 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 234 ((struct ip *)ui)->ip_ttl = udp_ttl; 235 return (ip_output(m, inp->inp_options, &inp->inp_route, 236 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); 237 } 238 239 int udp_sendspace = 2048; /* really max datagram size */ 240 int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ 241 242 /*ARGSUSED*/ 243 udp_usrreq(so, req, m, nam, rights) 244 struct socket *so; 245 int req; 246 struct mbuf *m, *nam, *rights; 247 { 248 struct inpcb *inp = sotoinpcb(so); 249 int error = 0; 250 251 if (req == PRU_CONTROL) 252 return (in_control(so, (int)m, (caddr_t)nam, 253 (struct ifnet *)rights)); 254 if (rights && rights->m_len) { 255 error = EINVAL; 256 goto release; 257 } 258 if (inp == NULL && req != PRU_ATTACH) { 259 error = EINVAL; 260 goto release; 261 } 262 switch (req) { 263 264 case PRU_ATTACH: 265 if (inp != NULL) { 266 error = EINVAL; 267 break; 268 } 269 error = in_pcballoc(so, &udb); 270 if (error) 271 break; 272 error = soreserve(so, udp_sendspace, udp_recvspace); 273 if (error) 274 break; 275 break; 276 277 case PRU_DETACH: 278 in_pcbdetach(inp); 279 break; 280 281 case PRU_BIND: 282 error = in_pcbbind(inp, nam); 283 break; 284 285 case PRU_LISTEN: 286 error = EOPNOTSUPP; 287 break; 288 289 case PRU_CONNECT: 290 if (inp->inp_faddr.s_addr != INADDR_ANY) { 291 error = EISCONN; 292 break; 293 } 294 error = in_pcbconnect(inp, nam); 295 if (error == 0) 296 soisconnected(so); 297 break; 298 299 case PRU_CONNECT2: 300 error = EOPNOTSUPP; 301 break; 302 303 case PRU_ACCEPT: 304 error = EOPNOTSUPP; 305 break; 306 307 case PRU_DISCONNECT: 308 if (inp->inp_faddr.s_addr == INADDR_ANY) { 309 error = ENOTCONN; 310 break; 311 } 312 in_pcbdisconnect(inp); 313 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 314 break; 315 316 case PRU_SHUTDOWN: 317 socantsendmore(so); 318 break; 319 320 case PRU_SEND: { 321 struct in_addr laddr; 322 int s; 323 324 if (nam) { 325 laddr = inp->inp_laddr; 326 if (inp->inp_faddr.s_addr != INADDR_ANY) { 327 error = EISCONN; 328 break; 329 } 330 /* 331 * Must block input while temporarily connected. 332 */ 333 s = splnet(); 334 error = in_pcbconnect(inp, nam); 335 if (error) { 336 splx(s); 337 break; 338 } 339 } else { 340 if (inp->inp_faddr.s_addr == INADDR_ANY) { 341 error = ENOTCONN; 342 break; 343 } 344 } 345 error = udp_output(inp, m); 346 m = NULL; 347 if (nam) { 348 in_pcbdisconnect(inp); 349 inp->inp_laddr = laddr; 350 splx(s); 351 } 352 } 353 break; 354 355 case PRU_ABORT: 356 in_pcbdetach(inp); 357 sofree(so); 358 soisdisconnected(so); 359 break; 360 361 case PRU_SOCKADDR: 362 in_setsockaddr(inp, nam); 363 break; 364 365 case PRU_PEERADDR: 366 in_setpeeraddr(inp, nam); 367 break; 368 369 case PRU_SENSE: 370 /* 371 * stat: don't bother with a blocksize. 372 */ 373 return (0); 374 375 case PRU_SENDOOB: 376 case PRU_FASTTIMO: 377 case PRU_SLOWTIMO: 378 case PRU_PROTORCV: 379 case PRU_PROTOSEND: 380 error = EOPNOTSUPP; 381 break; 382 383 case PRU_RCVD: 384 case PRU_RCVOOB: 385 return (EOPNOTSUPP); /* do not free mbuf's */ 386 387 default: 388 panic("udp_usrreq"); 389 } 390 release: 391 if (m != NULL) 392 m_freem(m); 393 return (error); 394 } 395