static mblk_t *get_as_yuvmsg(MSFilter *f, DecData *s, AVFrame *orig){ AVCodecContext *ctx=&s->av_context; if (s->outbuf.w!=ctx->width || s->outbuf.h!=ctx->height){ if (s->sws_ctx!=NULL){ sws_freeContext(s->sws_ctx); s->sws_ctx=NULL; freemsg(s->yuv_msg); s->yuv_msg=NULL; } ms_message("Getting yuv picture of %ix%i",ctx->width,ctx->height); s->yuv_msg=ms_yuv_buf_alloc(&s->outbuf,ctx->width,ctx->height); s->outbuf.w=ctx->width; s->outbuf.h=ctx->height; s->sws_ctx=sws_getContext(ctx->width,ctx->height,ctx->pix_fmt, ctx->width,ctx->height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR, NULL, NULL, NULL); ms_filter_notify_no_arg(f,MS_FILTER_OUTPUT_FMT_CHANGED); } #if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0,9,0) if (sws_scale(s->sws_ctx,(const uint8_t * const *)orig->data,orig->linesize, 0, ctx->height, s->outbuf.planes, s->outbuf.strides)<0){ #else if (sws_scale(s->sws_ctx,(uint8_t **)orig->data,orig->linesize, 0, ctx->height, s->outbuf.planes, s->outbuf.strides)<0){ #endif ms_error("%s: error in sws_scale().",f->desc->name); } return dupmsg(s->yuv_msg); } static void update_sps(DecData *d, mblk_t *sps){ if (d->sps) freemsg(d->sps); d->sps=dupb(sps); } static void update_pps(DecData *d, mblk_t *pps){ if (d->pps) freemsg(d->pps); if (pps) d->pps=dupb(pps); else d->pps=NULL; } static bool_t check_sps_change(DecData *d, mblk_t *sps){ bool_t ret=FALSE; if (d->sps){ ret=(msgdsize(sps)!=msgdsize(d->sps)) || (memcmp(d->sps->b_rptr,sps->b_rptr,msgdsize(sps))!=0); if (ret) { ms_message("SPS changed ! %i,%i",(int)msgdsize(sps),(int)msgdsize(d->sps)); update_sps(d,sps); update_pps(d,NULL); } } else { ms_message("Receiving first SPS"); update_sps(d,sps); } return ret; }
/* * Return a chain of mblks representing the Multidata packet. */ mblk_t * mmd_transform_link(pdesc_t *pd) { multidata_t *mmd; pdescinfo_t *pdi; mblk_t *nmp = NULL; ASSERT(pd != NULL); ASSERT(pd->pd_magic == PDESC_MAGIC); mmd = pd->pd_slab->pds_mmd; ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC); /* entry has been removed */ if (pd->pd_flags & PDESC_REM_DEFER) return (NULL); pdi = &(pd->pd_pdi); /* duplicate header buffer */ if ((pdi->flags & PDESC_HBUF_REF)) { if ((nmp = dupb(mmd->mmd_hbuf)) == NULL) return (NULL); nmp->b_rptr = pdi->hdr_rptr; nmp->b_wptr = pdi->hdr_wptr; } /* duplicate payload buffer(s) */ if (pdi->flags & PDESC_PBUF_REF) { int i; mblk_t *mp; struct pld_ary_s *pa = &pdi->pld_ary[0]; mutex_enter(&mmd->mmd_pd_slab_lock); for (i = 0; i < pdi->pld_cnt; i++, pa++) { ASSERT(mmd->mmd_pbuf[pa->pld_pbuf_idx] != NULL); /* skip empty ones */ if (PDESC_PLD_SPAN_SIZE(pdi, i) == 0) continue; mp = dupb(mmd->mmd_pbuf[pa->pld_pbuf_idx]); if (mp == NULL) { if (nmp != NULL) freemsg(nmp); mutex_exit(&mmd->mmd_pd_slab_lock); return (NULL); } mp->b_rptr = pa->pld_rptr; mp->b_wptr = pa->pld_wptr; if (nmp == NULL) nmp = mp; else linkb(nmp, mp); } mutex_exit(&mmd->mmd_pd_slab_lock); } return (nmp); }
/* duplicates a complex mblk_t */ mblk_t *dupmsg(mblk_t* m) { mblk_t *newm=NULL,*mp,*prev; prev=newm=dupb(m); m=m->b_cont; while (m!=NULL){ mp=dupb(m); prev->b_cont=mp; prev=mp; m=m->b_cont; } return newm; }
mblk_t * nl7c_http_persist(struct sonode *so) { uint64_t flags = so->so_nl7c_flags & NL7C_SCHEMEPRIV; mblk_t *mp; if (flags & HTTP_CONN_CL) mp = dupb(http_conn_cl); else if (flags & HTTP_CONN_KA) mp = dupb(http_conn_ka); else mp = NULL; return (mp); }
/* * Given a request with it's body already composed, * rewind to the start and fill in the SMB header. * This is called after the request is enqueued, * so we have the final MID, seq num. etc. */ void smb_rq_fillhdr(struct smb_rq *rqp) { struct mbchain mbtmp, *mbp = &mbtmp; mblk_t *m; /* * Fill in the SMB header using a dup of the first mblk, * which points at the same data but has its own wptr, * so we can rewind without trashing the message. */ m = dupb(rqp->sr_rq.mb_top); m->b_wptr = m->b_rptr; /* rewind */ mb_initm(mbp, m); mb_put_mem(mbp, SMB_SIGNATURE, 4, MB_MSYSTEM); mb_put_uint8(mbp, rqp->sr_cmd); mb_put_uint32le(mbp, 0); /* status */ mb_put_uint8(mbp, rqp->sr_rqflags); mb_put_uint16le(mbp, rqp->sr_rqflags2); mb_put_uint16le(mbp, 0); /* pid-high */ mb_put_mem(mbp, NULL, 8, MB_MZERO); /* MAC sig. (later) */ mb_put_uint16le(mbp, 0); /* reserved */ mb_put_uint16le(mbp, rqp->sr_rqtid); mb_put_uint16le(mbp, rqp->sr_pid); mb_put_uint16le(mbp, rqp->sr_rquid); mb_put_uint16le(mbp, rqp->sr_mid); /* This will free the mblk from dupb. */ mb_done(mbp); }
void split_and_queue(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded) { mblk_t *mdata,*tmp; int header_size; *discarded=0; header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc); if ((mp->b_wptr - mp->b_rptr)==header_size){ ortp_debug("Rtp packet contains no data."); (*discarded)++; freemsg(mp); return; } /* creates a new mblk_t to be linked with the rtp header*/ mdata=dupb(mp); mp->b_wptr=mp->b_rptr+header_size; mdata->b_rptr+=header_size; /* link proto with data */ mp->b_cont=mdata; /* and then add the packet to the queue */ rtp_putq(q,mp); /* make some checks: q size must not exceed RtpStream::max_rq_size */ while (q->q_mcount > maxrqsz) { /* remove the oldest mblk_t */ tmp=getq(q); if (mp!=NULL) { ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp); freemsg(tmp); (*discarded)++; } } }
static void dec_process_frame(MSFilter *f, DecState *s, ogg_packet *op){ yuv_buffer yuv; if (theora_decode_packetin(&s->tstate,op)==0){ if (theora_decode_YUVout(&s->tstate,&yuv)==0){ mblk_t *om; int i; int ylen=yuv.y_width*yuv.y_height; int uvlen=yuv.uv_width*yuv.uv_height; ms_debug("Got yuv buffer from theora decoder"); if (s->yuv==NULL){ int len=(ylen)+(2*uvlen); s->yuv=allocb(len,0); } om=dupb(s->yuv); for(i=0;i<yuv.y_height;++i){ memcpy(om->b_wptr,yuv.y+yuv.y_stride*i,yuv.y_width); om->b_wptr+=yuv.y_width; } for(i=0;i<yuv.uv_height;++i){ memcpy(om->b_wptr,yuv.u+yuv.uv_stride*i,yuv.uv_width); om->b_wptr+=yuv.uv_width; } for(i=0;i<yuv.uv_height;++i){ memcpy(om->b_wptr,yuv.v+yuv.uv_stride*i,yuv.uv_width); om->b_wptr+=yuv.uv_width; } ms_queue_put(f->outputs[0],om); } }else{ ms_warning("theora decoding error"); } }
bool_t xdrmblk_getmblk(XDR *xdrs, mblk_t **mm, uint_t *lenp) { mblk_t *m, *nextm; struct xdrmblk_params *p; int len; uint32_t llen; if (!xdrmblk_getint32(xdrs, (int32_t *)&llen)) return (FALSE); *lenp = llen; /* LINTED pointer alignment */ m = (mblk_t *)xdrs->x_base; *mm = m; /* * Walk the mblk chain until we get to the end or we've gathered * enough data. */ len = 0; llen = roundup(llen, BYTES_PER_XDR_UNIT); while (m != NULL && len + (int)MBLKL(m) <= llen) { len += (int)MBLKL(m); m = m->b_cont; } if (len < llen) { if (m == NULL) { return (FALSE); } else { int tail_bytes = llen - len; /* * Split the mblk with the last chunk of data and * insert it into the chain. The new mblk goes * after the existing one so that it will get freed * properly. */ nextm = dupb(m); if (nextm == NULL) return (FALSE); nextm->b_cont = m->b_cont; m->b_cont = nextm; m->b_wptr = m->b_rptr + tail_bytes; nextm->b_rptr += tail_bytes; ASSERT(nextm->b_rptr != nextm->b_wptr); m = nextm; /* for x_base */ } } xdrs->x_base = (caddr_t)m; xdrs->x_handy = m != NULL ? MBLKL(m) : 0; p = (struct xdrmblk_params *)xdrs->x_private; p->apos += p->rpos + llen; p->rpos = 0; return (TRUE); }
static void mire_process(MSFilter *f){ MireData *d=(MireData*)f->data; float elapsed=(float)(f->ticker->time-d->starttime); if ((elapsed*d->fps/1000.0)>d->index){ mire_draw(d); ms_queue_put(f->outputs[0],dupb(d->pic)); d->index++; } }
static void vp8_fragment_and_send(MSFilter *f,EncState *s,mblk_t *frame, uint32_t timestamp, const vpx_codec_cx_pkt_t *pkt, bool_t lastPartition){ uint8_t *rptr; mblk_t *packet=NULL; mblk_t* vp8_payload_desc = NULL; int len; #if 0 if ((pkt->data.frame.flags & VPX_FRAME_IS_KEY) == 0) { ms_debug("P-FRAME: %u\n", pkt->data.frame.sz); } else { ms_debug("I-FRAME: %u\n", pkt->data.frame.sz); } #endif for (rptr=frame->b_rptr;rptr<frame->b_wptr;){ vp8_payload_desc = allocb(1, 0); vp8_payload_desc->b_wptr=vp8_payload_desc->b_rptr+1; len=MIN(s->mtu,(frame->b_wptr-rptr)); packet=dupb(frame); packet->b_rptr=rptr; packet->b_wptr=rptr+len; mblk_set_timestamp_info(packet,timestamp); mblk_set_timestamp_info(vp8_payload_desc,timestamp); /* insert 1 byte vp8 payload descriptor */ (*vp8_payload_desc->b_rptr) = 0; /* X (extended) field, 0 */ (*vp8_payload_desc->b_rptr) &= ~VP8_PAYLOAD_DESC_X_MASK; /* RSV field, always 0 */ (*vp8_payload_desc->b_rptr) &= ~VP8_PAYLOAD_DESC_RSV_MASK; /* N : set to 1 if non reference frame */ if ((pkt->data.frame.flags & VPX_FRAME_IS_KEY) == 0) (*vp8_payload_desc->b_rptr) |= VP8_PAYLOAD_DESC_N_MASK; /* S : partition start */ if (rptr == frame->b_rptr) { (*vp8_payload_desc->b_rptr) |= VP8_PAYLOAD_DESC_S_MASK; } /* PartID : partition id */ #ifdef FRAGMENT_ON_PARTITIONS (*vp8_payload_desc->b_rptr) |= (pkt->data.frame.partition_id & VP8_PAYLOAD_DESC_PARTID_MASK); #endif vp8_payload_desc->b_cont = packet; ms_queue_put(f->outputs[0], vp8_payload_desc); rptr+=len; } freeb(frame); /*set marker bit on last packet*/ if (lastPartition) { mblk_set_marker_info(packet,TRUE); mblk_set_marker_info(vp8_payload_desc,TRUE); } }
/* * Return duplicate message block(s) of the associated buffer(s). */ int mmd_dupbufs(multidata_t *mmd, mblk_t **hmp, mblk_t **pmp) { ASSERT(mmd != NULL); ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC); if (hmp != NULL) { *hmp = NULL; if (mmd->mmd_hbuf != NULL && (*hmp = dupb(mmd->mmd_hbuf)) == NULL) return (-1); } if (pmp != NULL) { int i; mblk_t *mp; mutex_enter(&mmd->mmd_pd_slab_lock); *pmp = NULL; for (i = 0; i < mmd->mmd_pbuf_cnt; i++) { ASSERT(mmd->mmd_pbuf[i] != NULL); mp = dupb(mmd->mmd_pbuf[i]); if (mp == NULL) { if (hmp != NULL && *hmp != NULL) freeb(*hmp); if (*pmp != NULL) freemsg(*pmp); mutex_exit(&mmd->mmd_pd_slab_lock); return (-1); } if (*pmp == NULL) *pmp = mp; else linkb(*pmp, mp); } mutex_exit(&mmd->mmd_pd_slab_lock); } return (0); }
void static_image_process(MSFilter *f){ SIData *d=(SIData*)f->data; /*output a frame every second*/ if ((f->ticker->time - d->lasttime>1000) || d->lasttime==0){ if (d->pic) { mblk_t *o=dupb(d->pic); /*prevent mirroring at the output*/ mblk_set_precious_flag(o,1); ms_queue_put(f->outputs[0],o); } d->lasttime=f->ticker->time; } }
static void msv4l2_process(MSFilter *f){ V4l2State *s=(V4l2State*)f->data; #ifdef V4L2_THREADED uint32_t timestamp; int cur_frame; if (s->frame_count==-1){ s->start_time=f->ticker->time; s->frame_count=0; } cur_frame=((f->ticker->time-s->start_time)*s->fps/1000.0); if (cur_frame>=s->frame_count){ mblk_t *om=NULL; ms_mutex_lock(&s->mutex); /*keep the most recent frame if several frames have been captured */ if (s->fd!=-1){ om=getq(&s->rq); } ms_mutex_unlock(&s->mutex); if (om!=NULL){ timestamp=f->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/ mblk_set_timestamp_info(om,timestamp); mblk_set_marker_info(om,TRUE); ms_queue_put(f->outputs[0],om); /*ms_message("picture sent");*/ s->frame_count++; } }else{ flushq(&s->rq,0); } #else uint32_t elapsed; if (s->fd!=-1){ /*see it is necessary to output a frame:*/ elapsed=f->ticker->time-s->start_time; if (((float)elapsed*s->fps/1000.0)>s->frame_count){ mblk_t *m; m=v4lv2_grab_image(s); if (m){ mblk_t *om=dupb(m); mblk_set_marker_info(om,(s->pix_fmt==MS_MJPEG)); ms_queue_put(f->outputs[0],om); s->frame_count++; } } } #endif }
static void *msv4l2_thread(void *ptr){ V4l2State *s=(V4l2State*)ptr; int err=-1; ms_message("msv4l2_thread starting"); if (s->fd!=-1) { ms_warning("msv4l2 file descriptor already openned fd:%d",s->fd); goto exit; } if( msv4l2_open(s)!=0){ ms_warning("msv4l2 could not be openned"); goto close; } if (!s->configured && msv4l2_configure(s)!=0){ ms_warning("msv4l2 could not be configured"); goto close; } if (msv4l2_do_mmap(s)!=0) { ms_warning("msv4l2 do mmap"); goto close; } ms_message("V4L2 video capture started."); while(s->thread_run) { mblk_t *m; if (s->fd!=-1){ mblk_t *m; m=v4lv2_grab_image(s); if (m){ mblk_t *om=dupb(m); mblk_set_marker_info(om,(s->pix_fmt==MS_MJPEG)); ms_mutex_lock(&s->mutex); putq(&s->rq,om); ms_mutex_unlock(&s->mutex); } } } ms_message("thread:%d",s->thread_run); munmap: msv4l2_do_munmap(s); close: msv4l2_close(s); exit: ms_message("msv4l2_thread exited."); s->fd = -1; ms_thread_exit(NULL); }
mblk_t *msgb_allocator_alloc(msgb_allocator_t *a, int size){ queue_t *q=&a->q; mblk_t *m,*found=NULL; /*lookup for an unused msgb (data block with ref count ==1)*/ for(m=qbegin(q);!qend(q,m);m=qnext(q,m)){ if (m->b_datap->db_ref==1 && m->b_datap->db_lim-m->b_datap->db_base>=size){ found=m; break; } } if (found==NULL){ found=allocb(size,0); putq(q,found); } return dupb(found); }
/*process incoming rtp data and output NALUs, whenever possible*/ void rfc3984_unpack(Rfc3984Context *ctx, mblk_t *im, MSQueue *out){ uint8_t type=nal_header_get_type(im->b_rptr); uint8_t *p; if (im->b_cont) msgpullup(im,-1); if (type==TYPE_STAP_A){ ms_message("Receiving STAP-A"); /*split into nalus*/ uint16_t sz; uint8_t *buf=(uint8_t*)&sz; mblk_t *nal; for(p=im->b_rptr+1;p<im->b_wptr;){ buf[0]=p[0]; buf[1]=p[1]; sz=ntohs(sz); nal=dupb(im); p+=2; nal->b_rptr=p; p+=sz; nal->b_wptr=p; if (p>im->b_wptr){ ms_error("Malformed STAP-A packet"); freemsg(nal); break; } ms_queue_put(&ctx->q,nal); } freemsg(im); }else if (type==TYPE_FU_A){ ms_message("Receiving FU-A"); mblk_t *o=aggregate_fua(ctx,im); if (o) ms_queue_put(&ctx->q,o); }else{ /*single nal unit*/ ms_message("Receiving single NAL"); ms_queue_put(&ctx->q,im); } if (mblk_get_marker_info(im)){ /*end of frame, output everything*/ while(!ms_queue_empty(&ctx->q)){ ms_queue_put(out,ms_queue_get(&ctx->q)); } } }
static void v4l2_process(MSFilter *f){ V4l2State *s=(V4l2State*)f->data; uint32_t elapsed; if (s->fd!=-1){ /*see it is necessary to output a frame:*/ elapsed=f->ticker->time-s->start_time; if (((float)elapsed*s->fps/1000.0)>s->frame_count){ mblk_t *m; m=v4lv2_grab_image(s); if (m){ mblk_t *om=dupb(m); mblk_set_marker_info(om,(s->pix_fmt==MS_MJPEG)); ms_queue_put(f->outputs[0],om); s->frame_count++; } } } }
static void frag_nalu_and_send(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bool_t marker, int maxsize){ mblk_t *m; int payload_max_size=maxsize-2;/*minus FUA header*/ uint8_t fu_indicator; uint8_t type=nal_header_get_type(nalu->b_rptr); uint8_t nri=nal_header_get_nri(nalu->b_rptr); bool_t start=TRUE; nal_header_init(&fu_indicator,nri,TYPE_FU_A); while(nalu->b_wptr-nalu->b_rptr>payload_max_size){ m=dupb(nalu); nalu->b_rptr+=payload_max_size; m->b_wptr=nalu->b_rptr; m=prepend_fu_indicator_and_header(m,fu_indicator,start,FALSE,type); send_packet(rtpq,ts,m,FALSE); start=FALSE; } /*send last packet */ m=prepend_fu_indicator_and_header(nalu,fu_indicator,FALSE,TRUE,type); send_packet(rtpq,ts,m,marker); }
static void packetize_and_send(MSFilter *f, EncState *s, mblk_t *om, uint32_t timestamp, uint8_t tdt){ mblk_t *packet; mblk_t *h; int npackets=0; static const int ident=0xdede; while(om!=NULL){ if (om->b_wptr-om->b_rptr>=s->mtu){ packet=dupb(om); packet->b_wptr=packet->b_rptr+s->mtu; om->b_rptr=packet->b_wptr; }else { packet=om; om=NULL; } ++npackets; h=allocb(6,0); if (npackets==1){ if (om==NULL) payload_header_set(h->b_wptr,ident,NOT_FRAGMENTED,tdt,1); else payload_header_set(h->b_wptr,ident,START_FRAGMENT,tdt,1); }else{ if (om==NULL) payload_header_set(h->b_wptr,ident,END_FRAGMENT,tdt,1); else payload_header_set(h->b_wptr,ident,CONT_FRAGMENT,tdt,1); } h->b_wptr+=4; *((uint16_t*)h->b_wptr)=htons(msgdsize(packet)); h->b_wptr+=2; h->b_cont=packet; mblk_set_timestamp_info(h,timestamp); ms_debug("sending theora frame of size %i",msgdsize(h)); ms_queue_put(f->outputs[0],h); } }
static void winsnd_write_process(MSFilter *f){ WinSnd *d=(WinSnd*)f->data; mblk_t *m,*old; MMRESULT mr; int i; int discarded=0; int possible_size=0; if (d->outdev==NULL) { ms_queue_flush(f->inputs[0]); return; } while((m=ms_queue_get(f->inputs[0]))!=NULL){ possible_size = msgdsize(m); #ifndef DISABLE_SPEEX if (d->pst_frame_size==0) { d->pst_frame_size=possible_size; d->pst = speex_preprocess_state_init(d->pst_frame_size/2, d->wfx.nSamplesPerSec); if (d->pst!=NULL) { float f; i=1; speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_VAD, &i); i=0; speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DENOISE, &i); i=0; speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC, &i); f=8000; speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); i=0; speex_preprocess_ctl(d->pst, SPEEX_PREPROCESS_SET_DEREVERB, &i); } } #endif putq(&d->write_rq,m); } #ifdef AMD_HACK /* too many sound card are crappy on windows... */ d->stat_minimumbuffer=15; if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ d->stat_minimumbuffer=8; #endif if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ { if (d->nbufs_playing+d->write_rq.q_mcount<4) { d->ready=0; } } else { if (d->nbufs_playing+d->write_rq.q_mcount<7) { d->ready=0; } } #if defined(WCE_OPTICON_WORKAROUND) if (d->workaround==0) { d->workaround=1; Sleep(WCE_OPTICON_WORKAROUND); } #endif while((m=peekq(&d->write_rq))!=NULL){ #ifndef DISABLE_SPEEX int vad=1; if (d->pst!=NULL && msgdsize(m)==d->pst_frame_size && d->pst_frame_size<=4096) { char tmp[4096]; memcpy(tmp, m->b_rptr, msgdsize(m)); vad = speex_preprocess(d->pst, (short*)tmp, NULL); if (d->ready==0) { if (vad==0) { int missing; missing = 10 - d->write_rq.q_mcount - d->nbufs_playing; if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ missing = 6 - d->write_rq.q_mcount - d->nbufs_playing; ms_message("WINSND trouble: inserting %i silence", missing); while(missing>0) { old=dupb(m); putq(&d->write_rq,old); missing--; } } d->ready=1; } } #else if (d->ready==0) { int missing; missing = 10 - d->write_rq.q_mcount - d->nbufs_playing; if (d->wfx.nSamplesPerSec>=32000) /* better results for high rates */ missing = 6 - d->write_rq.q_mcount - d->nbufs_playing; ms_message("WINSND trouble: inserting %i silence", missing); while(missing>0) { old=dupb(m); putq(&d->write_rq,old); missing--; } d->ready=1; } #endif for(i=0;i<d->stat_minimumbuffer;++i){ WAVEHDR *hdr=&d->hdrs_write[i]; if (hdr->dwFlags & WHDR_DONE){ old=(mblk_t*)hdr->dwUser; mr=waveOutUnprepareHeader(d->outdev,hdr,sizeof(*hdr)); if (mr != MMSYSERR_NOERROR){ ms_error("waveOutUnprepareHeader error"); } freemsg(old); hdr->dwUser=0; } if (hdr->dwUser==0){ hdr->lpData=(LPSTR)m->b_rptr; hdr->dwBufferLength=msgdsize(m); hdr->dwFlags = 0; hdr->dwUser = (DWORD)m; mr = waveOutPrepareHeader(d->outdev,hdr,sizeof(*hdr)); if (mr != MMSYSERR_NOERROR){ ms_error("waveOutPrepareHeader() error"); getq(&d->write_rq); freemsg(m); discarded++; d->stat_notplayed++; break; } mr=waveOutWrite(d->outdev,hdr,sizeof(*hdr)); if (mr != MMSYSERR_NOERROR){ ms_error("waveOutWrite() error"); getq(&d->write_rq); freemsg(m); discarded++; d->stat_notplayed++; break; }else { getq(&d->write_rq); d->nbufs_playing++; /* ms_debug("waveOutWrite() done"); */ } break; } } if (i==d->stat_minimumbuffer){ //ms_error("winsnd_write_process: All buffers are busy."); #ifndef DISABLE_SPEEX if (d->pst==NULL) { /* initial behavior (detection in process?) */ getq(&d->write_rq); freemsg(m); discarded++; d->stat_notplayed++; } else { if (vad==0) { getq(&d->write_rq); freemsg(m); ms_message("WINSND trouble: silence removed"); discarded++; d->stat_notplayed++; } } #else getq(&d->write_rq); freemsg(m); discarded++; d->stat_notplayed++; #endif break; } } }
static void update_pps(DecData *d, mblk_t *pps){ if (d->pps) freemsg(d->pps); if (pps) d->pps=dupb(pps); else d->pps=NULL; }
static void update_sps(DecData *d, mblk_t *sps){ if (d->sps) freemsg(d->sps); d->sps=dupb(sps); }
static int hxge_start(p_hxge_t hxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp) { int dma_status, status = 0; p_tx_desc_t tx_desc_ring_vp; hpi_handle_t hpi_desc_handle; hxge_os_dma_handle_t tx_desc_dma_handle; p_tx_desc_t tx_desc_p; p_tx_msg_t tx_msg_ring; p_tx_msg_t tx_msg_p; tx_desc_t tx_desc, *tmp_desc_p; tx_desc_t sop_tx_desc, *sop_tx_desc_p; p_tx_pkt_header_t hdrp; p_tx_pkt_hdr_all_t pkthdrp; uint8_t npads = 0; uint64_t dma_ioaddr; uint32_t dma_flags; int last_bidx; uint8_t *b_rptr; caddr_t kaddr; uint32_t nmblks; uint32_t ngathers; uint32_t clen; int len; uint32_t pkt_len, pack_len, min_len; uint32_t bcopy_thresh; int i, cur_index, sop_index; uint16_t tail_index; boolean_t tail_wrap = B_FALSE; hxge_dma_common_t desc_area; hxge_os_dma_handle_t dma_handle; ddi_dma_cookie_t dma_cookie; hpi_handle_t hpi_handle; p_mblk_t nmp; p_mblk_t t_mp; uint32_t ncookies; boolean_t good_packet; boolean_t mark_mode = B_FALSE; p_hxge_stats_t statsp; p_hxge_tx_ring_stats_t tdc_stats; t_uscalar_t start_offset = 0; t_uscalar_t stuff_offset = 0; t_uscalar_t end_offset = 0; t_uscalar_t value = 0; t_uscalar_t cksum_flags = 0; boolean_t cksum_on = B_FALSE; uint32_t boff = 0; uint64_t tot_xfer_len = 0, tmp_len = 0; boolean_t header_set = B_FALSE; tdc_tdr_kick_t kick; uint32_t offset; #ifdef HXGE_DEBUG p_tx_desc_t tx_desc_ring_pp; p_tx_desc_t tx_desc_pp; tx_desc_t *save_desc_p; int dump_len; int sad_len; uint64_t sad; int xfer_len; uint32_t msgsize; #endif HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: tx dma channel %d", tx_ring_p->tdc)); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: Starting tdc %d desc pending %d", tx_ring_p->tdc, tx_ring_p->descs_pending)); statsp = hxgep->statsp; if (hxgep->statsp->port_stats.lb_mode == hxge_lb_normal) { if (!statsp->mac_stats.link_up) { freemsg(mp); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: " "link not up or LB mode")); goto hxge_start_fail1; } } mac_hcksum_get(mp, &start_offset, &stuff_offset, &end_offset, &value, &cksum_flags); if (!HXGE_IS_VLAN_PACKET(mp->b_rptr)) { start_offset += sizeof (ether_header_t); stuff_offset += sizeof (ether_header_t); } else { start_offset += sizeof (struct ether_vlan_header); stuff_offset += sizeof (struct ether_vlan_header); } if (cksum_flags & HCK_PARTIALCKSUM) { HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: mp $%p len %d " "cksum_flags 0x%x (partial checksum) ", mp, MBLKL(mp), cksum_flags)); cksum_on = B_TRUE; } MUTEX_ENTER(&tx_ring_p->lock); start_again: ngathers = 0; sop_index = tx_ring_p->wr_index; #ifdef HXGE_DEBUG if (tx_ring_p->descs_pending) { HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: desc pending %d ", tx_ring_p->descs_pending)); } dump_len = (int)(MBLKL(mp)); dump_len = (dump_len > 128) ? 128: dump_len; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: tdc %d: dumping ...: b_rptr $%p " "(Before header reserve: ORIGINAL LEN %d)", tx_ring_p->tdc, mp->b_rptr, dump_len)); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: dump packets (IP ORIGINAL b_rptr $%p): %s", mp->b_rptr, hxge_dump_packet((char *)mp->b_rptr, dump_len))); #endif tdc_stats = tx_ring_p->tdc_stats; mark_mode = (tx_ring_p->descs_pending && ((tx_ring_p->tx_ring_size - tx_ring_p->descs_pending) < hxge_tx_minfree)); HXGE_DEBUG_MSG((hxgep, TX_CTL, "TX Descriptor ring is channel %d mark mode %d", tx_ring_p->tdc, mark_mode)); if (!hxge_txdma_reclaim(hxgep, tx_ring_p, hxge_tx_minfree)) { HXGE_DEBUG_MSG((hxgep, TX_CTL, "TX Descriptor ring is full: channel %d", tx_ring_p->tdc)); HXGE_DEBUG_MSG((hxgep, TX_CTL, "TX Descriptor ring is full: channel %d", tx_ring_p->tdc)); (void) atomic_cas_32((uint32_t *)&tx_ring_p->queueing, 0, 1); tdc_stats->tx_no_desc++; MUTEX_EXIT(&tx_ring_p->lock); status = 1; goto hxge_start_fail1; } nmp = mp; i = sop_index = tx_ring_p->wr_index; nmblks = 0; ngathers = 0; pkt_len = 0; pack_len = 0; clen = 0; last_bidx = -1; good_packet = B_TRUE; desc_area = tx_ring_p->tdc_desc; hpi_handle = desc_area.hpi_handle; hpi_desc_handle.regh = (hxge_os_acc_handle_t) DMA_COMMON_ACC_HANDLE(desc_area); hpi_desc_handle.hxgep = hxgep; tx_desc_ring_vp = (p_tx_desc_t)DMA_COMMON_VPTR(desc_area); #ifdef HXGE_DEBUG #if defined(__i386) tx_desc_ring_pp = (p_tx_desc_t)(uint32_t)DMA_COMMON_IOADDR(desc_area); #else tx_desc_ring_pp = (p_tx_desc_t)DMA_COMMON_IOADDR(desc_area); #endif #endif tx_desc_dma_handle = (hxge_os_dma_handle_t)DMA_COMMON_HANDLE(desc_area); tx_msg_ring = tx_ring_p->tx_msg_ring; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: wr_index %d i %d", sop_index, i)); #ifdef HXGE_DEBUG msgsize = msgdsize(nmp); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(1): wr_index %d i %d msgdsize %d", sop_index, i, msgsize)); #endif /* * The first 16 bytes of the premapped buffer are reserved * for header. No padding will be used. */ pkt_len = pack_len = boff = TX_PKT_HEADER_SIZE; if (hxge_tx_use_bcopy) { bcopy_thresh = (hxge_bcopy_thresh - TX_PKT_HEADER_SIZE); } else { bcopy_thresh = (TX_BCOPY_SIZE - TX_PKT_HEADER_SIZE); } while (nmp) { good_packet = B_TRUE; b_rptr = nmp->b_rptr; len = MBLKL(nmp); if (len <= 0) { nmp = nmp->b_cont; continue; } nmblks++; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(1): nmblks %d " "len %d pkt_len %d pack_len %d", nmblks, len, pkt_len, pack_len)); /* * Hardware limits the transfer length to 4K. * If len is more than 4K, we need to break * nmp into two chunks: Make first chunk smaller * than 4K. The second chunk will be broken into * less than 4K (if needed) during the next pass. */ if (len > (TX_MAX_TRANSFER_LENGTH - TX_PKT_HEADER_SIZE)) { if ((t_mp = dupb(nmp)) != NULL) { nmp->b_wptr = nmp->b_rptr + (TX_MAX_TRANSFER_LENGTH - TX_PKT_HEADER_SIZE); t_mp->b_rptr = nmp->b_wptr; t_mp->b_cont = nmp->b_cont; nmp->b_cont = t_mp; len = MBLKL(nmp); } else { good_packet = B_FALSE; goto hxge_start_fail2; } } tx_desc.value = 0; tx_desc_p = &tx_desc_ring_vp[i]; #ifdef HXGE_DEBUG tx_desc_pp = &tx_desc_ring_pp[i]; #endif tx_msg_p = &tx_msg_ring[i]; #if defined(__i386) hpi_desc_handle.regp = (uint32_t)tx_desc_p; #else hpi_desc_handle.regp = (uint64_t)tx_desc_p; #endif if (!header_set && ((!hxge_tx_use_bcopy && (len > TX_BCOPY_SIZE)) || (len >= bcopy_thresh))) { header_set = B_TRUE; bcopy_thresh += TX_PKT_HEADER_SIZE; boff = 0; pack_len = 0; kaddr = (caddr_t)DMA_COMMON_VPTR(tx_msg_p->buf_dma); hdrp = (p_tx_pkt_header_t)kaddr; clen = pkt_len; dma_handle = tx_msg_p->buf_dma_handle; dma_ioaddr = DMA_COMMON_IOADDR(tx_msg_p->buf_dma); offset = tx_msg_p->offset_index * hxge_bcopy_thresh; (void) ddi_dma_sync(dma_handle, offset, hxge_bcopy_thresh, DDI_DMA_SYNC_FORDEV); tx_msg_p->flags.dma_type = USE_BCOPY; goto hxge_start_control_header_only; } pkt_len += len; pack_len += len; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(3): desc entry %d DESC IOADDR $%p " "desc_vp $%p tx_desc_p $%p desc_pp $%p tx_desc_pp $%p " "len %d pkt_len %d pack_len %d", i, DMA_COMMON_IOADDR(desc_area), tx_desc_ring_vp, tx_desc_p, tx_desc_ring_pp, tx_desc_pp, len, pkt_len, pack_len)); if (len < bcopy_thresh) { HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(4): USE BCOPY: ")); if (hxge_tx_tiny_pack) { uint32_t blst = TXDMA_DESC_NEXT_INDEX(i, -1, tx_ring_p->tx_wrap_mask); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(5): pack")); if ((pack_len <= bcopy_thresh) && (last_bidx == blst)) { HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: pack(6) " "(pkt_len %d pack_len %d)", pkt_len, pack_len)); i = blst; tx_desc_p = &tx_desc_ring_vp[i]; #ifdef HXGE_DEBUG tx_desc_pp = &tx_desc_ring_pp[i]; #endif tx_msg_p = &tx_msg_ring[i]; boff = pack_len - len; ngathers--; } else if (pack_len > bcopy_thresh && header_set) { pack_len = len; boff = 0; bcopy_thresh = hxge_bcopy_thresh; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(7): > max NEW " "bcopy thresh %d " "pkt_len %d pack_len %d(next)", bcopy_thresh, pkt_len, pack_len)); } last_bidx = i; } kaddr = (caddr_t)DMA_COMMON_VPTR(tx_msg_p->buf_dma); if ((boff == TX_PKT_HEADER_SIZE) && (nmblks == 1)) { hdrp = (p_tx_pkt_header_t)kaddr; header_set = B_TRUE; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(7_x2): " "pkt_len %d pack_len %d (new hdrp $%p)", pkt_len, pack_len, hdrp)); } tx_msg_p->flags.dma_type = USE_BCOPY; kaddr += boff; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(8): USE BCOPY: before bcopy " "DESC IOADDR $%p entry %d bcopy packets %d " "bcopy kaddr $%p bcopy ioaddr (SAD) $%p " "bcopy clen %d bcopy boff %d", DMA_COMMON_IOADDR(desc_area), i, tdc_stats->tx_hdr_pkts, kaddr, dma_ioaddr, clen, boff)); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: 1USE BCOPY: ")); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: 2USE BCOPY: ")); HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: " "last USE BCOPY: copy from b_rptr $%p " "to KADDR $%p (len %d offset %d", b_rptr, kaddr, len, boff)); bcopy(b_rptr, kaddr, len); #ifdef HXGE_DEBUG dump_len = (len > 128) ? 128: len; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: dump packets " "(After BCOPY len %d)" "(b_rptr $%p): %s", len, nmp->b_rptr, hxge_dump_packet((char *)nmp->b_rptr, dump_len))); #endif dma_handle = tx_msg_p->buf_dma_handle; dma_ioaddr = DMA_COMMON_IOADDR(tx_msg_p->buf_dma); offset = tx_msg_p->offset_index * hxge_bcopy_thresh; (void) ddi_dma_sync(dma_handle, offset, hxge_bcopy_thresh, DDI_DMA_SYNC_FORDEV); clen = len + boff; tdc_stats->tx_hdr_pkts++; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(9): " "USE BCOPY: DESC IOADDR $%p entry %d " "bcopy packets %d bcopy kaddr $%p " "bcopy ioaddr (SAD) $%p bcopy clen %d " "bcopy boff %d", DMA_COMMON_IOADDR(desc_area), i, tdc_stats->tx_hdr_pkts, kaddr, dma_ioaddr, clen, boff)); } else { HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(12): USE DVMA: len %d", len)); tx_msg_p->flags.dma_type = USE_DMA; dma_flags = DDI_DMA_WRITE; if (len < hxge_dma_stream_thresh) { dma_flags |= DDI_DMA_CONSISTENT; } else { dma_flags |= DDI_DMA_STREAMING; } dma_handle = tx_msg_p->dma_handle; dma_status = ddi_dma_addr_bind_handle(dma_handle, NULL, (caddr_t)b_rptr, len, dma_flags, DDI_DMA_DONTWAIT, NULL, &dma_cookie, &ncookies); if (dma_status == DDI_DMA_MAPPED) { dma_ioaddr = dma_cookie.dmac_laddress; len = (int)dma_cookie.dmac_size; clen = (uint32_t)dma_cookie.dmac_size; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(12_1): " "USE DVMA: len %d clen %d ngathers %d", len, clen, ngathers)); #if defined(__i386) hpi_desc_handle.regp = (uint32_t)tx_desc_p; #else hpi_desc_handle.regp = (uint64_t)tx_desc_p; #endif while (ncookies > 1) { ngathers++; /* * this is the fix for multiple * cookies, which are basically * a descriptor entry, we don't set * SOP bit as well as related fields */ (void) hpi_txdma_desc_gather_set( hpi_desc_handle, &tx_desc, (ngathers -1), mark_mode, ngathers, dma_ioaddr, clen); tx_msg_p->tx_msg_size = clen; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: DMA " "ncookie %d ngathers %d " "dma_ioaddr $%p len %d" "desc $%p descp $%p (%d)", ncookies, ngathers, dma_ioaddr, clen, *tx_desc_p, tx_desc_p, i)); ddi_dma_nextcookie(dma_handle, &dma_cookie); dma_ioaddr = dma_cookie.dmac_laddress; len = (int)dma_cookie.dmac_size; clen = (uint32_t)dma_cookie.dmac_size; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start(12_2): " "USE DVMA: len %d clen %d ", len, clen)); i = TXDMA_DESC_NEXT_INDEX(i, 1, tx_ring_p->tx_wrap_mask); tx_desc_p = &tx_desc_ring_vp[i]; hpi_desc_handle.regp = #if defined(__i386) (uint32_t)tx_desc_p; #else (uint64_t)tx_desc_p; #endif tx_msg_p = &tx_msg_ring[i]; tx_msg_p->flags.dma_type = USE_NONE; tx_desc.value = 0; ncookies--; } tdc_stats->tx_ddi_pkts++; HXGE_DEBUG_MSG((hxgep, TX_CTL, "==> hxge_start: DMA: ddi packets %d", tdc_stats->tx_ddi_pkts)); } else { HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "dma mapping failed for %d " "bytes addr $%p flags %x (%d)", len, b_rptr, status, status)); good_packet = B_FALSE; tdc_stats->tx_dma_bind_fail++; tx_msg_p->flags.dma_type = USE_NONE; status = 1; goto hxge_start_fail2; } } /* ddi dvma */ nmp = nmp->b_cont; hxge_start_control_header_only: #if defined(__i386) hpi_desc_handle.regp = (uint32_t)tx_desc_p; #else hpi_desc_handle.regp = (uint64_t)tx_desc_p; #endif ngathers++; if (ngathers == 1) { #ifdef HXGE_DEBUG save_desc_p = &sop_tx_desc; #endif sop_tx_desc_p = &sop_tx_desc; sop_tx_desc_p->value = 0; sop_tx_desc_p->bits.tr_len = clen; sop_tx_desc_p->bits.sad = dma_ioaddr >> 32; sop_tx_desc_p->bits.sad_l = dma_ioaddr & 0xffffffff; } else {
void sctp_wput_asconf(sctp_t *sctp, sctp_faddr_t *fp) { #define SCTP_SET_SENT_FLAG(mp) ((mp)->b_flag = SCTP_CHUNK_FLAG_SENT) mblk_t *mp; mblk_t *ipmp; uint32_t *snp; sctp_parm_hdr_t *ph; boolean_t isv4; sctp_stack_t *sctps = sctp->sctp_sctps; boolean_t saddr_set; if (sctp->sctp_cchunk_pend || sctp->sctp_cxmit_list == NULL || /* Queue it for later transmission if not yet established */ sctp->sctp_state < SCTPS_ESTABLISHED) { ip2dbg(("sctp_wput_asconf: cchunk pending? (%d) or null "\ "sctp_cxmit_list? (%s) or incorrect state? (%x)\n", sctp->sctp_cchunk_pend, sctp->sctp_cxmit_list == NULL ? "yes" : "no", sctp->sctp_state)); return; } if (fp == NULL) fp = sctp->sctp_current; /* OK to send */ ipmp = sctp_make_mp(sctp, fp, 0); if (ipmp == NULL) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); SCTP_KSTAT(sctps, sctp_send_asconf_failed); return; } mp = sctp->sctp_cxmit_list; /* Fill in the mandatory Address Parameter TLV */ isv4 = (fp != NULL) ? fp->isv4 : sctp->sctp_current->isv4; ph = (sctp_parm_hdr_t *)(mp->b_rptr + sizeof (sctp_chunk_hdr_t) + sizeof (uint32_t)); if (isv4) { ipha_t *ipha = (ipha_t *)ipmp->b_rptr; in6_addr_t ipaddr; ipaddr_t addr4; ph->sph_type = htons(PARM_ADDR4); ph->sph_len = htons(PARM_ADDR4_LEN); if (ipha->ipha_src != INADDR_ANY) { bcopy(&ipha->ipha_src, ph + 1, IP_ADDR_LEN); } else { ipaddr = sctp_get_valid_addr(sctp, B_FALSE, &saddr_set); /* * All the addresses are down. * Maybe we might have better luck next time. */ if (!saddr_set) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); freeb(ipmp); return; } IN6_V4MAPPED_TO_IPADDR(&ipaddr, addr4); bcopy(&addr4, ph + 1, IP_ADDR_LEN); } } else { ip6_t *ip6 = (ip6_t *)ipmp->b_rptr; in6_addr_t ipaddr; ph->sph_type = htons(PARM_ADDR6); ph->sph_len = htons(PARM_ADDR6_LEN); if (!IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { bcopy(&ip6->ip6_src, ph + 1, IPV6_ADDR_LEN); } else { ipaddr = sctp_get_valid_addr(sctp, B_TRUE, &saddr_set); /* * All the addresses are down. * Maybe we might have better luck next time. */ if (!saddr_set) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); freeb(ipmp); return; } bcopy(&ipaddr, ph + 1, IPV6_ADDR_LEN); } } /* Don't exceed CWND */ if ((MBLKL(mp) > (fp->cwnd - fp->suna)) || ((mp = dupb(sctp->sctp_cxmit_list)) == NULL)) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); freeb(ipmp); return; } /* Set the serial number now, if sending for the first time */ if (!SCTP_CHUNK_WANT_REXMIT(mp)) { snp = (uint32_t *)(mp->b_rptr + sizeof (sctp_chunk_hdr_t)); *snp = htonl(sctp->sctp_lcsn++); } SCTP_CHUNK_CLEAR_FLAGS(mp); fp->suna += MBLKL(mp); /* Attach the header and send the chunk */ ipmp->b_cont = mp; sctp->sctp_cchunk_pend = 1; SCTP_SET_SENT_FLAG(sctp->sctp_cxmit_list); SCTP_SET_CHUNK_DEST(sctp->sctp_cxmit_list, fp); sctp_set_iplen(sctp, ipmp, fp->ixa); (void) conn_ip_output(ipmp, fp->ixa); BUMP_LOCAL(sctp->sctp_opkts); SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); #undef SCTP_SET_SENT_FLAG }
/* * This routine is called from read put/service procedure and parses * message block to check for telnet protocol by detecting an IAC. * The routine processes the data part of the message block first and * then sends protocol followed after IAC to the telnet daemon. The * routine also processes CR/LF by eliminating LF/NULL followed after CR. * * Since the code to do this with streams mblks is complicated, some * explanations are in order. If an IAC is found, a dupb() is done, * and the pointers are adjusted to create two streams message. The * (possibly empty) first message contains preceeding data, and the * second begins with the IAC and contains the rest of the streams * message. * * The variables: * datamp: Points to the head of a chain of mblks containing data * which requires no expansion, and can be forwarded directly * to the pty. * prevmp: Points to the last mblk on the datamp chain, used to add * to the chain headed by datamp. * newmp: When an M_CTL header is required, this pointer references * that "header" mblk. * protomp: When an IAC is discovered, a dupb() is done on the first mblk * containing an IAC. protomp points to this dup'ed mblk. * This mblk is eventually forwarded to the daemon. */ static int rcv_parse(queue_t *q, mblk_t *mp) { mblk_t *protomp, *newmp, *datamp, *prevmp; unsigned char *tmp; size_t msgsize; struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; datamp = mp; prevmp = protomp = 0; while (mp) { /* * If the mblk is empty, just continue scanning. */ if (mp->b_rptr == mp->b_wptr) { prevmp = mp; mp = mp->b_cont; continue; } /* * First check to see if we have received CR and are checking * for a following LF/NULL. If so, do what's necessary to * trim the LF/NULL. This case is for when the LF/NULL is * at the beginning of a subsequent mblk. */ if (!(tmip->flags & TEL_BINARY_IN) && (tmip->flags & TEL_CRRCV)) { if ((*mp->b_rptr == '\n') || (*mp->b_rptr == NULL)) { if (mp->b_wptr == (mp->b_rptr + 1)) { tmip->flags &= ~TEL_CRRCV; if (prevmp) { prevmp->b_cont = mp->b_cont; freeb(mp); mp = prevmp->b_cont; continue; } else { datamp = mp->b_cont; freeb(mp); if (datamp == NULL) { /* * Message contained * only a '\0' after * a '\r' in a previous * message, so we can * read more, even * though we have * nothing to putnext. */ return (1); } else { mp = datamp; continue; } } } mp->b_rptr += 1; } tmip->flags &= ~TEL_CRRCV; } tmp = mp->b_rptr; /* * Now scan through the entire message block, for IACs * and CR characters, which need processing. */ while (tmp < mp->b_wptr) { if (tmp[0] == IAC) { /* * Telnet protocol - parse it now * process data part of mblk * before sending the protocol. */ if (tmp > mp->b_rptr) { if ((protomp = dupb(mp)) == NULL) { msgsize = msgdsize(datamp); recover(q, datamp, msgsize); return (0); } ASSERT(tmp >= mp->b_datap->db_base); ASSERT(tmp <= mp->b_datap->db_lim); ASSERT(tmp >= protomp->b_datap->db_base); ASSERT(tmp <= protomp->b_datap->db_lim); mp->b_wptr = tmp; protomp->b_rptr = tmp; protomp->b_cont = mp->b_cont; mp->b_cont = 0; if (prevmp) prevmp->b_cont = mp; } else { protomp = mp; if (prevmp) prevmp->b_cont = 0; else datamp = 0; } if (datamp) { putnext(q, datamp); } /* * create a 1 byte M_CTL message block with * protomp and send it down. */ if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) { /* * Save the dup'ed mp containing * the protocol information which * we couldn't get an M_CTL header * for. */ msgsize = msgdsize(protomp); recover(q, protomp, msgsize); return (0); } newmp->b_datap->db_type = M_CTL; newmp->b_wptr = newmp->b_rptr + 1; *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; newmp->b_cont = protomp; noenable(q); tmip->flags |= TEL_STOPPED; putnext(q, newmp); return (0); } if (!(tmip->flags & TEL_BINARY_IN)) { /* * Set TEL_CRRCV flag if last character is CR */ if ((tmp == (mp->b_wptr - 1)) && (tmp[0] == '\r')) { tmip->flags |= TEL_CRRCV; break; } /* * If CR is followed by LF/NULL, get rid of * LF/NULL and realign the message block. */ if ((tmp[0] == '\r') && ((tmp[1] == '\n') || (tmp[1] == NULL))) { /* * If CR is in the middle of a block, * we need to get rid of LF and join * the two pieces together. */ if (mp->b_wptr > (tmp + 2)) { bcopy(tmp + 2, tmp + 1, (mp->b_wptr - tmp - 2)); mp->b_wptr -= 1; } else { mp->b_wptr = tmp + 1; } if (prevmp) prevmp->b_cont = mp; } } tmp++; } prevmp = mp; mp = mp->b_cont; } putnext(q, datamp); return (1); }