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