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