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