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