| 1 | /* udp_usrreq.c 4.19 82/01/19 */ |
| 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 "../net/in.h" |
| 11 | #include "../net/in_pcb.h" |
| 12 | #include "../net/in_systm.h" |
| 13 | #include "../net/ip.h" |
| 14 | #include "../net/ip_var.h" |
| 15 | #include "../net/udp.h" |
| 16 | #include "../net/udp_var.h" |
| 17 | |
| 18 | /* |
| 19 | * UDP protocol implementation. |
| 20 | * Per RFC 768, August, 1980. |
| 21 | */ |
| 22 | udp_init() |
| 23 | { |
| 24 | |
| 25 | COUNT(UDP_INIT); |
| 26 | udb.inp_next = udb.inp_prev = &udb; |
| 27 | } |
| 28 | |
| 29 | int udpcksum; |
| 30 | struct sockaddr_in udp_in = { AF_INET }; |
| 31 | |
| 32 | udp_input(m0) |
| 33 | struct mbuf *m0; |
| 34 | { |
| 35 | register struct udpiphdr *ui; |
| 36 | register struct inpcb *inp; |
| 37 | register struct mbuf *m; |
| 38 | int len, ulen; |
| 39 | |
| 40 | COUNT(UDP_INPUT); |
| 41 | /* |
| 42 | * Get IP and UDP header together in first mbuf. |
| 43 | */ |
| 44 | m = m0; |
| 45 | if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && |
| 46 | (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { |
| 47 | udpstat.udps_hdrops++; |
| 48 | return; |
| 49 | } |
| 50 | ui = mtod(m, struct udpiphdr *); |
| 51 | if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) |
| 52 | ip_stripoptions((struct ip *)ui, (struct mbuf *)0); |
| 53 | |
| 54 | /* |
| 55 | * Make mbuf data length reflect UDP length. |
| 56 | * If not enough data to reflect UDP length, drop. |
| 57 | */ |
| 58 | ulen = ntohs((u_short)ui->ui_ulen); |
| 59 | len = sizeof (struct udphdr) + ulen; |
| 60 | if (((struct ip *)ui)->ip_len != len) { |
| 61 | if (len > ((struct ip *)ui)->ip_len) { |
| 62 | udpstat.udps_badlen++; |
| 63 | goto bad; |
| 64 | } |
| 65 | m_adj(m, ((struct ip *)ui)->ip_len - len); |
| 66 | /* (struct ip *)ui->ip_len = len; */ |
| 67 | } |
| 68 | |
| 69 | /* |
| 70 | * Checksum extended UDP header and data. |
| 71 | */ |
| 72 | if (udpcksum) { |
| 73 | ui->ui_next = ui->ui_prev = 0; |
| 74 | ui->ui_x1 = 0; |
| 75 | ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen)); |
| 76 | if (ui->ui_sum = in_cksum(m, len)) { |
| 77 | udpstat.udps_badsum++; |
| 78 | printf("udp cksum %x\n", ui->ui_sum); |
| 79 | m_freem(m); |
| 80 | return; |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | /* |
| 85 | * Locate pcb for datagram. |
| 86 | */ |
| 87 | inp = in_pcblookup(&udb, |
| 88 | ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport); |
| 89 | if (inp == 0) |
| 90 | goto bad; |
| 91 | |
| 92 | /* |
| 93 | * Construct sockaddr format source address. |
| 94 | * Stuff source address and datagram in user buffer. |
| 95 | */ |
| 96 | udp_in.sin_port = ui->ui_sport; |
| 97 | udp_in.sin_addr = ui->ui_src; |
| 98 | m->m_len -= sizeof (struct udpiphdr); |
| 99 | m->m_off += sizeof (struct udpiphdr); |
| 100 | if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) |
| 101 | goto bad; |
| 102 | sorwakeup(inp->inp_socket); |
| 103 | return; |
| 104 | bad: |
| 105 | m_freem(m); |
| 106 | } |
| 107 | |
| 108 | udp_ctlinput(m) |
| 109 | struct mbuf *m; |
| 110 | { |
| 111 | |
| 112 | COUNT(UDP_CTLINPUT); |
| 113 | m_freem(m); |
| 114 | } |
| 115 | |
| 116 | udp_output(inp, m0) |
| 117 | struct inpcb *inp; |
| 118 | struct mbuf *m0; |
| 119 | { |
| 120 | register struct mbuf *m; |
| 121 | register struct udpiphdr *ui; |
| 122 | register int len = 0; |
| 123 | |
| 124 | COUNT(UDP_OUTPUT); |
| 125 | /* |
| 126 | * Calculate data length and get a mbuf |
| 127 | * for UDP and IP headers. |
| 128 | */ |
| 129 | for (m = m0; m; m = m->m_next) |
| 130 | len += m->m_len; |
| 131 | m = m_get(M_DONTWAIT); |
| 132 | if (m == 0) |
| 133 | goto bad; |
| 134 | |
| 135 | /* |
| 136 | * Fill in mbuf with extended UDP header |
| 137 | * and addresses and length put into network format. |
| 138 | */ |
| 139 | m->m_off = MMAXOFF - sizeof (struct udpiphdr); |
| 140 | m->m_len = sizeof (struct udpiphdr); |
| 141 | m->m_next = m0; |
| 142 | ui = mtod(m, struct udpiphdr *); |
| 143 | ui->ui_next = ui->ui_prev = 0; |
| 144 | ui->ui_x1 = 0; |
| 145 | ui->ui_pr = IPPROTO_UDP; |
| 146 | ui->ui_len = sizeof (struct udpiphdr) + len; |
| 147 | ui->ui_src = inp->inp_laddr; |
| 148 | ui->ui_dst = inp->inp_faddr; |
| 149 | ui->ui_sport = inp->inp_lport; |
| 150 | ui->ui_dport = inp->inp_fport; |
| 151 | ui->ui_ulen = htons((u_short)len); |
| 152 | |
| 153 | /* |
| 154 | * Stuff checksum and output datagram. |
| 155 | */ |
| 156 | ui->ui_sum = 0; |
| 157 | ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len); |
| 158 | ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; |
| 159 | ((struct ip *)ui)->ip_ttl = MAXTTL; |
| 160 | (void) ip_output(m, (struct mbuf *)0); |
| 161 | return; |
| 162 | bad: |
| 163 | m_freem(m); |
| 164 | } |
| 165 | |
| 166 | udp_usrreq(so, req, m, addr) |
| 167 | struct socket *so; |
| 168 | int req; |
| 169 | struct mbuf *m; |
| 170 | caddr_t addr; |
| 171 | { |
| 172 | struct inpcb *inp = sotoinpcb(so); |
| 173 | int error; |
| 174 | |
| 175 | COUNT(UDP_USRREQ); |
| 176 | if (inp == 0 && req != PRU_ATTACH) |
| 177 | return (EINVAL); |
| 178 | switch (req) { |
| 179 | |
| 180 | case PRU_ATTACH: |
| 181 | if (inp != 0) |
| 182 | return (EINVAL); |
| 183 | error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); |
| 184 | if (error) |
| 185 | return (error); |
| 186 | break; |
| 187 | |
| 188 | case PRU_DETACH: |
| 189 | if (inp == 0) |
| 190 | return (ENOTCONN); |
| 191 | in_pcbdetach(inp); |
| 192 | break; |
| 193 | |
| 194 | case PRU_CONNECT: |
| 195 | if (inp->inp_faddr.s_addr) |
| 196 | return (EISCONN); |
| 197 | error = in_pcbconnect(inp, (struct sockaddr_in *)addr); |
| 198 | if (error) |
| 199 | return (error); |
| 200 | soisconnected(so); |
| 201 | break; |
| 202 | |
| 203 | case PRU_ACCEPT: |
| 204 | return (EOPNOTSUPP); |
| 205 | |
| 206 | case PRU_DISCONNECT: |
| 207 | if (inp->inp_faddr.s_addr == 0) |
| 208 | return (ENOTCONN); |
| 209 | in_pcbdisconnect(inp); |
| 210 | soisdisconnected(so); |
| 211 | break; |
| 212 | |
| 213 | case PRU_SHUTDOWN: |
| 214 | socantsendmore(so); |
| 215 | break; |
| 216 | |
| 217 | case PRU_SEND: |
| 218 | if (addr) { |
| 219 | if (inp->inp_faddr.s_addr) |
| 220 | return (EISCONN); |
| 221 | error = in_pcbconnect(inp, (struct sockaddr_in *)addr); |
| 222 | if (error) |
| 223 | return (error); |
| 224 | } else { |
| 225 | if (inp->inp_faddr.s_addr == 0) |
| 226 | return (ENOTCONN); |
| 227 | } |
| 228 | udp_output(inp, m); |
| 229 | if (addr) |
| 230 | in_pcbdisconnect(inp); |
| 231 | break; |
| 232 | |
| 233 | case PRU_ABORT: |
| 234 | in_pcbdetach(inp); |
| 235 | sofree(so); |
| 236 | soisdisconnected(so); |
| 237 | break; |
| 238 | |
| 239 | case PRU_CONTROL: |
| 240 | return (EOPNOTSUPP); |
| 241 | |
| 242 | default: |
| 243 | panic("udp_usrreq"); |
| 244 | } |
| 245 | return (0); |
| 246 | } |