1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)udp_usrreq.c 7.14 (Berkeley) 05/17/90 18 */ 19 20 #include "param.h" 21 #include "user.h" 22 #include "malloc.h" 23 #include "mbuf.h" 24 #include "protosw.h" 25 #include "socket.h" 26 #include "socketvar.h" 27 #include "errno.h" 28 #include "stat.h" 29 30 #include "../net/if.h" 31 #include "../net/route.h" 32 33 #include "in.h" 34 #include "in_systm.h" 35 #include "ip.h" 36 #include "in_pcb.h" 37 #include "ip_var.h" 38 #include "ip_icmp.h" 39 #include "udp.h" 40 #include "udp_var.h" 41 42 /* 43 * UDP protocol implementation. 44 * Per RFC 768, August, 1980. 45 */ 46 udp_init() 47 { 48 49 udb.inp_next = udb.inp_prev = &udb; 50 } 51 52 #ifndef COMPAT_42 53 int udpcksum = 1; 54 #else 55 int udpcksum = 0; /* XXX */ 56 #endif 57 int udp_ttl = UDP_TTL; 58 59 struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; 60 61 udp_input(m, iphlen) 62 register struct mbuf *m; 63 int iphlen; 64 { 65 register struct ip *ip; 66 register struct udphdr *uh; 67 register struct inpcb *inp; 68 int len; 69 struct ip save_ip; 70 71 #ifndef notyet 72 if (iphlen > sizeof (struct ip)) 73 ip_stripoptions(m, (struct mbuf *)0); 74 #endif 75 /* 76 * Get IP and UDP header together in first mbuf. 77 */ 78 ip = mtod(m, struct ip *); 79 if (m->m_len < iphlen + sizeof(struct udphdr)) { 80 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { 81 udpstat.udps_hdrops++; 82 return; 83 } 84 ip = mtod(m, struct ip *); 85 } 86 uh = (struct udphdr *)((caddr_t)ip + iphlen); 87 88 /* 89 * Make mbuf data length reflect UDP length. 90 * If not enough data to reflect UDP length, drop. 91 */ 92 len = ntohs((u_short)uh->uh_ulen); 93 if (ip->ip_len != len) { 94 if (len > ip->ip_len) { 95 udpstat.udps_badlen++; 96 goto bad; 97 } 98 m_adj(m, len - ip->ip_len); 99 /* ip->ip_len = len; */ 100 } 101 /* 102 * Save a copy of the IP header in case we want restore it 103 * for sending an ICMP error message in response. 104 */ 105 save_ip = *ip; 106 107 /* 108 * Checksum extended UDP header and data. 109 */ 110 if (udpcksum && uh->uh_sum) { 111 ((struct ipovly *)ip)->ih_next = 0; 112 ((struct ipovly *)ip)->ih_prev = 0; 113 ((struct ipovly *)ip)->ih_x1 = 0; 114 ((struct ipovly *)ip)->ih_len = uh->uh_ulen; 115 if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) { 116 udpstat.udps_badsum++; 117 m_freem(m); 118 return; 119 } 120 } 121 122 /* 123 * Locate pcb for datagram. 124 */ 125 inp = in_pcblookup(&udb, 126 ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, 127 INPLOOKUP_WILDCARD); 128 if (inp == 0) { 129 /* don't send ICMP response for broadcast packet */ 130 udpstat.udps_noport++; 131 if (m->m_flags & M_BCAST) 132 goto bad; 133 *ip = save_ip; 134 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT); 135 return; 136 } 137 138 /* 139 * Construct sockaddr format source address. 140 * Stuff source address and datagram in user buffer. 141 */ 142 udp_in.sin_port = uh->uh_sport; 143 udp_in.sin_addr = ip->ip_src; 144 iphlen = sizeof(struct ip); 145 iphlen += sizeof(struct udphdr); 146 m->m_len -= iphlen; 147 m->m_pkthdr.len -= iphlen; 148 m->m_data += iphlen; 149 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, 150 m, (struct mbuf *)0) == 0) 151 goto bad; 152 udpstat.udps_ipackets++; 153 sorwakeup(inp->inp_socket); 154 return; 155 bad: 156 m_freem(m); 157 } 158 159 /* 160 * Notify a udp user of an asynchronous error; 161 * just wake up so that he can collect error status. 162 */ 163 udp_notify(inp) 164 register struct inpcb *inp; 165 { 166 167 sorwakeup(inp->inp_socket); 168 sowwakeup(inp->inp_socket); 169 } 170 171 udp_ctlinput(cmd, sa, ip) 172 int cmd; 173 struct sockaddr *sa; 174 register struct ip *ip; 175 { 176 register struct udphdr *uh; 177 extern struct in_addr zeroin_addr; 178 extern u_char inetctlerrmap[]; 179 180 if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) 181 return; 182 if (ip) { 183 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 184 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, 185 cmd, udp_notify); 186 } else 187 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); 188 } 189 190 udp_output(inp, m, addr, control) 191 register struct inpcb *inp; 192 register struct mbuf *m; 193 struct mbuf *addr, *control; 194 { 195 register struct udpiphdr *ui; 196 register int len = m->m_pkthdr.len; 197 struct in_addr laddr; 198 int s, error = 0; 199 200 if (control) 201 m_freem(control); /* XXX */ 202 203 if (addr) { 204 laddr = inp->inp_laddr; 205 if (inp->inp_faddr.s_addr != INADDR_ANY) { 206 error = EISCONN; 207 goto release; 208 } 209 /* 210 * Must block input while temporarily connected. 211 */ 212 s = splnet(); 213 error = in_pcbconnect(inp, addr); 214 if (error) { 215 splx(s); 216 goto release; 217 } 218 } else { 219 if (inp->inp_faddr.s_addr == INADDR_ANY) { 220 error = ENOTCONN; 221 goto release; 222 } 223 } 224 /* 225 * Calculate data length and get a mbuf 226 * for UDP and IP headers. 227 */ 228 M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT); 229 230 /* 231 * Fill in mbuf with extended UDP header 232 * and addresses and length put into network format. 233 */ 234 ui = mtod(m, struct udpiphdr *); 235 ui->ui_next = ui->ui_prev = 0; 236 ui->ui_x1 = 0; 237 ui->ui_pr = IPPROTO_UDP; 238 ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); 239 ui->ui_src = inp->inp_laddr; 240 ui->ui_dst = inp->inp_faddr; 241 ui->ui_sport = inp->inp_lport; 242 ui->ui_dport = inp->inp_fport; 243 ui->ui_ulen = ui->ui_len; 244 245 /* 246 * Stuff checksum and output datagram. 247 */ 248 ui->ui_sum = 0; 249 if (udpcksum) { 250 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) 251 ui->ui_sum = 0xffff; 252 } 253 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 254 ((struct ip *)ui)->ip_ttl = udp_ttl; 255 udpstat.udps_opackets++; 256 error = ip_output(m, inp->inp_options, &inp->inp_route, 257 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)); 258 259 if (addr) { 260 in_pcbdisconnect(inp); 261 inp->inp_laddr = laddr; 262 splx(s); 263 } 264 return (error); 265 266 release: 267 m_freem(m); 268 return (error); 269 } 270 271 u_long udp_sendspace = 9216; /* really max datagram size */ 272 u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); 273 /* 40 1K datagrams */ 274 275 /*ARGSUSED*/ 276 udp_usrreq(so, req, m, addr, control) 277 struct socket *so; 278 int req; 279 struct mbuf *m, *addr, *control; 280 { 281 struct inpcb *inp = sotoinpcb(so); 282 int error = 0; 283 284 if (req == PRU_CONTROL) 285 return (in_control(so, (int)m, (caddr_t)addr, 286 (struct ifnet *)control)); 287 if (inp == NULL && req != PRU_ATTACH) { 288 error = EINVAL; 289 goto release; 290 } 291 switch (req) { 292 293 case PRU_ATTACH: 294 if (inp != NULL) { 295 error = EINVAL; 296 break; 297 } 298 error = in_pcballoc(so, &udb); 299 if (error) 300 break; 301 error = soreserve(so, udp_sendspace, udp_recvspace); 302 if (error) 303 break; 304 break; 305 306 case PRU_DETACH: 307 in_pcbdetach(inp); 308 break; 309 310 case PRU_BIND: 311 error = in_pcbbind(inp, addr); 312 break; 313 314 case PRU_LISTEN: 315 error = EOPNOTSUPP; 316 break; 317 318 case PRU_CONNECT: 319 if (inp->inp_faddr.s_addr != INADDR_ANY) { 320 error = EISCONN; 321 break; 322 } 323 error = in_pcbconnect(inp, addr); 324 if (error == 0) 325 soisconnected(so); 326 break; 327 328 case PRU_CONNECT2: 329 error = EOPNOTSUPP; 330 break; 331 332 case PRU_ACCEPT: 333 error = EOPNOTSUPP; 334 break; 335 336 case PRU_DISCONNECT: 337 if (inp->inp_faddr.s_addr == INADDR_ANY) { 338 error = ENOTCONN; 339 break; 340 } 341 in_pcbdisconnect(inp); 342 inp->inp_laddr.s_addr = INADDR_ANY; 343 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 344 break; 345 346 case PRU_SHUTDOWN: 347 socantsendmore(so); 348 break; 349 350 case PRU_SEND: 351 error = udp_output(inp, m, addr, control); 352 m = NULL; 353 control = NULL; 354 break; 355 356 case PRU_ABORT: 357 soisdisconnected(so); 358 in_pcbdetach(inp); 359 break; 360 361 case PRU_SOCKADDR: 362 in_setsockaddr(inp, addr); 363 break; 364 365 case PRU_PEERADDR: 366 in_setpeeraddr(inp, addr); 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 (control) { 392 printf("udp control data unexpectedly retained\n"); 393 m_freem(control); 394 } 395 if (m) 396 m_freem(m); 397 return (error); 398 } 399