1 /* ip_output.c 1.5 81/10/29 */ 2 3 #include "../h/param.h" 4 #include "../h/mbuf.h" 5 #include "../h/socket.h" 6 #include "../inet/inet.h" 7 #include "../inet/inet_systm.h" 8 #include "../inet/imp.h" 9 #include "../inet/inet_host.h" 10 #include "../inet/ip.h" 11 #include "../inet/tcp.h" 12 13 ip_output(mp) 14 struct mbuf *mp; 15 { 16 register i, rnd; 17 register struct mbuf *m, *n; 18 register struct ip *p; 19 struct mbuf *mm; 20 int hlen, adj, max, len, off; 21 22 COUNT(IP_OUTPUT); 23 p = (struct ip *)((int)mp + mp->m_off); /* -> ip header */ 24 hlen = sizeof (struct ip); /* header length */ 25 26 /* 27 * Fill in and byte swap ip header. 28 */ 29 p->ip_v = IPVERSION; 30 p->ip_hl = hlen >> 2; 31 p->ip_off = 0 | (p->ip_off & IP_DF); 32 p->ip_ttl = MAXTTL; 33 p->ip_id = ip_id++; 34 35 if (p->ip_len > MTU) { /* must fragment */ 36 if (p->ip_off & IP_DF) 37 return (0); 38 max = MTU - hlen; /* maximum data length in fragment */ 39 len = p->ip_len - hlen; /* data length */ 40 off = 0; /* fragment offset */ 41 m = mp; 42 43 while (len > 0) { 44 45 /* correct the header */ 46 47 p->ip_off |= off >> 3; 48 49 /* find the end of the fragment */ 50 51 i = -hlen; 52 while (m != NULL) { 53 i += m->m_len; 54 if (i > max) 55 break; 56 n = m; 57 m = m->m_next; 58 } 59 60 if (i < max || m == NULL) { /* last fragment */ 61 p->ip_off = p->ip_off &~ IP_MF; 62 p->ip_len = i + hlen; 63 break; 64 65 } else { /* more fragments */ 66 67 /* allocate header mbuf for next fragment */ 68 69 if ((mm = m_get(1)) == NULL) /* no more bufs */ 70 return(0); 71 72 p->ip_off |= IP_MF; 73 74 /* terminate fragment at 8 byte boundary (round down) */ 75 76 i -= m->m_len; 77 rnd = i & ~7; /* fragment length */ 78 adj = i - rnd; /* leftover in mbuf */ 79 p->ip_len = rnd + hlen; 80 81 /* setup header for next fragment and 82 append remaining fragment data */ 83 84 n->m_next = NULL; 85 mm->m_next = m; 86 m = mm; 87 m->m_off = MMAXOFF - hlen - adj; 88 m->m_len = hlen + adj; 89 90 /* copy old header to new */ 91 92 bcopy(p, (caddr_t)((int)m + m->m_off), hlen); 93 94 /* copy leftover data from previous frag */ 95 96 if (adj) { 97 n->m_len -= adj; 98 bcopy((caddr_t)((int)n + n->m_len + n->m_off), 99 (caddr_t)((int)m + m->m_off + hlen), adj); 100 } 101 } 102 103 ip_send(p); /* pass frag to local net level */ 104 105 p = (struct ip *)((int)m + m->m_off); /* -> new hdr */ 106 len -= rnd; 107 off += rnd; 108 } 109 } 110 111 return(ip_send(p)); /* pass datagram to local net level */ 112 } 113 114 ip_send(p) /* format header and send message to 1822 level */ 115 struct ip *p; 116 { 117 register struct mbuf *m; 118 register struct imp *l; 119 int s; 120 COUNT(IP_SEND); 121 122 m = dtom(p); /* ->header mbuf */ 123 124 /* set up 1822 leader fields for transmit */ 125 126 l = (struct imp *)((int)m + m->m_off - L1822); 127 /* 128 l->i_hst = p->ip_dst.s_host; 129 l->i_impno = p->ip_dst.s_imp; 130 l->i_mlen = p->ip_len + L1822; 131 l->i_link = IPLINK; 132 l->i_type = 0; 133 l->i_htype = 0; 134 l->i_stype = 0; 135 */ 136 if ((l->i_shost = p->ip_src.s_host) == 0) 137 l->i_shost = 253; 138 if ((l->i_dhost = p->ip_dst.s_host) == 0) 139 l->i_dhost = 253; 140 l->i_type = IPTYPE; 141 142 /* finish ip leader by calculating checksum and doing 143 necessary byte-swapping */ 144 145 p->ip_sum = 0; 146 p->ip_len = htons(p->ip_len); 147 p->ip_id = htons(p->ip_id); 148 p->ip_off = htons(p->ip_off); 149 p->ip_sum = cksum(m, sizeof(struct ip)); 150 151 m->m_off -= L1822; /* -> 1822 leader */ 152 m->m_len += L1822; 153 154 m->m_act = NULL; 155 156 #ifndef IMPLOOP 157 158 /* put output message on queue */ 159 160 s = splimp(); 161 if (imp_stat.outq_head != NULL) 162 imp_stat.outq_tail->m_act = m; 163 else 164 imp_stat.outq_head = m; 165 imp_stat.outq_tail = m; 166 splx(s); 167 168 /* if no outstanding output, start some */ 169 170 if (!imp_stat.outactive) 171 imp_output(0); 172 173 #else 174 /* software looping: put msg chain on input queue */ 175 176 if (imp_stat.inq_head != NULL) 177 imp_stat.inq_tail->m_act = m; 178 else 179 imp_stat.inq_head = m; 180 imp_stat.inq_tail = m; 181 182 #endif IMPLOOP 183 return (1); 184 } 185 186 ip_setup(up, m, len) /* setup an ip header for raw write */ 187 register struct ucb *up; 188 register struct mbuf *m; 189 int len; 190 { 191 register struct ip *ip; 192 COUNT(IP_SETUP); 193 194 m->m_off = MMAXOFF - sizeof(struct ip); 195 m->m_len = sizeof(struct ip); 196 197 ip = (struct ip *)((int)m + m->m_off); 198 199 ip->ip_tos = 0; 200 ip->ip_id = 0; 201 ip->ip_off = 0; 202 ip->ip_p = up->uc_lolink; 203 ip->ip_len = len + sizeof(struct ip); 204 205 ip->ip_src.s_addr = n_lhost.s_addr; 206 ip->ip_dst.s_addr = up->uc_host->h_addr.s_addr; 207 } 208