1 /* udp_usrreq.c 4.10 81/11/24 */ 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 if (m->m_len < sizeof (struct udpiphdr) && 44 m_pullup(m, sizeof (struct udpiphdr)) == 0) { 45 udpstat.udps_hdrops++; 46 goto bad; 47 } 48 ui = mtod(m, struct udpiphdr *); 49 if (ui->ui_len > sizeof (struct ip)) 50 ip_stripoptions((struct ip *)ui, (char *)0); 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)) != 0xffff) { 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 inp = in_pcblookup(&udb, 87 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport); 88 if (inp == 0) 89 goto bad; 90 91 /* 92 * Construct sockaddr format source address. 93 * Stuff source address and datagram in user buffer. 94 */ 95 udp_in.sin_port = ui->ui_sport; 96 udp_in.sin_addr = ui->ui_src; 97 m->m_len -= sizeof (struct udpiphdr); 98 m->m_off += sizeof (struct udpiphdr); 99 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0) 100 goto bad; 101 sorwakeup(inp->inp_socket); 102 return; 103 bad: 104 m_freem(m); 105 } 106 107 udp_ctlinput(m) 108 struct mbuf *m; 109 { 110 111 printf("udp_ctlinput\n"); 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 = sizeof (struct udpiphdr) + len; 146 ui->ui_src = inp->inp_laddr; 147 ui->ui_dst = inp->inp_faddr; 148 ui->ui_sport = inp->inp_lport; 149 ui->ui_dport = 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 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; 158 ((struct ip *)ui)->ip_ttl = MAXTTL; 159 ip_output(m); 160 return; 161 bad: 162 m_freem(m); 163 } 164 165 /*ARGSUSED*/ 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 if (inp == 0 && req != PRU_ATTACH) 176 return (EINVAL); 177 switch (req) { 178 179 case PRU_ATTACH: 180 if (inp != 0) 181 return (EINVAL); 182 error = in_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); 183 if (error) 184 return (error); 185 break; 186 187 case PRU_DETACH: 188 if (inp == 0) 189 return (ENOTCONN); 190 in_pcbfree(inp); 191 break; 192 193 case PRU_CONNECT: 194 if (inp->inp_faddr.s_addr) 195 return (EISCONN); 196 error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 197 if (error) 198 return (error); 199 soisconnected(so); 200 break; 201 202 case PRU_ACCEPT: 203 return (EOPNOTSUPP); 204 205 case PRU_DISCONNECT: 206 if (inp->inp_faddr.s_addr == 0) 207 return (ENOTCONN); 208 inp->inp_faddr.s_addr = 0; 209 soisdisconnected(so); 210 break; 211 212 case PRU_SHUTDOWN: 213 socantsendmore(so); 214 break; 215 216 case PRU_SEND: 217 if (addr) { 218 if (inp->inp_faddr.s_addr) 219 return (EISCONN); 220 error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 221 if (error) 222 return (error); 223 } else { 224 if (inp->inp_faddr.s_addr == 0) 225 return (ENOTCONN); 226 } 227 udp_output(inp, m); 228 if (addr) 229 inp->inp_faddr.s_addr = 0; 230 break; 231 232 case PRU_ABORT: 233 in_pcbfree(inp); 234 sofree(so); 235 soisdisconnected(so); 236 break; 237 238 case PRU_CONTROL: 239 return (EOPNOTSUPP); 240 241 default: 242 panic("udp_usrreq"); 243 } 244 return (0); 245 } 246 247 /*ARGSUSED*/ 248 udp_sense(m) 249 struct mbuf *m; 250 { 251 252 printf("udp_sense\n"); 253 return (EOPNOTSUPP); 254 } 255