@@ -63,19 +63,26 @@ static int get_var_len(const struct snd_seq_event *event)
6363 return event -> data .ext .len & ~SNDRV_SEQ_EXT_MASK ;
6464}
6565
66- int snd_seq_dump_var_event (const struct snd_seq_event * event ,
67- snd_seq_dump_func_t func , void * private_data )
66+ static int dump_var_event (const struct snd_seq_event * event ,
67+ snd_seq_dump_func_t func , void * private_data ,
68+ int offset , int maxlen )
6869{
6970 int len , err ;
7071 struct snd_seq_event_cell * cell ;
7172
7273 len = get_var_len (event );
7374 if (len <= 0 )
7475 return len ;
76+ if (len <= offset )
77+ return 0 ;
78+ if (maxlen && len > offset + maxlen )
79+ len = offset + maxlen ;
7580
7681 if (event -> data .ext .len & SNDRV_SEQ_EXT_USRPTR ) {
7782 char buf [32 ];
7883 char __user * curptr = (char __force __user * )event -> data .ext .ptr ;
84+ curptr += offset ;
85+ len -= offset ;
7986 while (len > 0 ) {
8087 int size = sizeof (buf );
8188 if (len < size )
@@ -91,20 +98,35 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
9198 return 0 ;
9299 }
93100 if (!(event -> data .ext .len & SNDRV_SEQ_EXT_CHAINED ))
94- return func (private_data , event -> data .ext .ptr , len );
101+ return func (private_data , event -> data .ext .ptr + offset ,
102+ len - offset );
95103
96104 cell = (struct snd_seq_event_cell * )event -> data .ext .ptr ;
97105 for (; len > 0 && cell ; cell = cell -> next ) {
98106 int size = sizeof (struct snd_seq_event );
107+ char * curptr = (char * )& cell -> event ;
108+
109+ if (offset >= size ) {
110+ offset -= size ;
111+ len -= size ;
112+ continue ;
113+ }
99114 if (len < size )
100115 size = len ;
101- err = func (private_data , & cell -> event , size );
116+ err = func (private_data , curptr + offset , size - offset );
102117 if (err < 0 )
103118 return err ;
119+ offset = 0 ;
104120 len -= size ;
105121 }
106122 return 0 ;
107123}
124+
125+ int snd_seq_dump_var_event (const struct snd_seq_event * event ,
126+ snd_seq_dump_func_t func , void * private_data )
127+ {
128+ return dump_var_event (event , func , private_data , 0 , 0 );
129+ }
108130EXPORT_SYMBOL (snd_seq_dump_var_event );
109131
110132
@@ -132,11 +154,27 @@ static int seq_copy_in_user(void *ptr, void *src, int size)
132154 return 0 ;
133155}
134156
157+ static int expand_var_event (const struct snd_seq_event * event ,
158+ int offset , int size , char * buf , bool in_kernel )
159+ {
160+ if (event -> data .ext .len & SNDRV_SEQ_EXT_USRPTR ) {
161+ if (! in_kernel )
162+ return - EINVAL ;
163+ if (copy_from_user (buf ,
164+ (char __force __user * )event -> data .ext .ptr + offset ,
165+ size ))
166+ return - EFAULT ;
167+ return 0 ;
168+ }
169+ return dump_var_event (event ,
170+ in_kernel ? seq_copy_in_kernel : seq_copy_in_user ,
171+ & buf , offset , size );
172+ }
173+
135174int snd_seq_expand_var_event (const struct snd_seq_event * event , int count , char * buf ,
136175 int in_kernel , int size_aligned )
137176{
138- int len , newlen ;
139- int err ;
177+ int len , newlen , err ;
140178
141179 len = get_var_len (event );
142180 if (len < 0 )
@@ -146,25 +184,35 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
146184 newlen = roundup (len , size_aligned );
147185 if (count < newlen )
148186 return - EAGAIN ;
149-
150- if (event -> data .ext .len & SNDRV_SEQ_EXT_USRPTR ) {
151- if (! in_kernel )
152- return - EINVAL ;
153- if (copy_from_user (buf , (void __force __user * )event -> data .ext .ptr , len ))
154- return - EFAULT ;
155- } else {
156- err = snd_seq_dump_var_event (event ,
157- in_kernel ? seq_copy_in_kernel : seq_copy_in_user ,
158- & buf );
159- if (err < 0 )
160- return err ;
161- }
187+ err = expand_var_event (event , 0 , len , buf , in_kernel );
188+ if (err < 0 )
189+ return err ;
162190 if (len != newlen )
163191 memset (buf + len , 0 , newlen - len );
164192 return newlen ;
165193}
166194EXPORT_SYMBOL (snd_seq_expand_var_event );
167195
196+ int snd_seq_expand_var_event_at (const struct snd_seq_event * event , int count ,
197+ char * buf , int offset )
198+ {
199+ int len , err ;
200+
201+ len = get_var_len (event );
202+ if (len < 0 )
203+ return len ;
204+ if (len <= offset )
205+ return 0 ;
206+ len -= offset ;
207+ if (len > count )
208+ len = count ;
209+ err = expand_var_event (event , offset , count , buf , true);
210+ if (err < 0 )
211+ return err ;
212+ return len ;
213+ }
214+ EXPORT_SYMBOL_GPL (snd_seq_expand_var_event_at );
215+
168216/*
169217 * release this cell, free extended data if available
170218 */
0 commit comments